General Scripting Questions

This topic contains 0 replies, has 1 voice, and was last updated by  Forums Archives 5 years, 9 months ago.

  • Author
    Posts
  • #5660

    by notarat at 2013-03-13 10:06:22

    I've been dutifully researching Power Shell in my efforts to be more efficient at my job. One of the reasons I use PS is to gather information that my office needs to identify potential issues. Things like pathnames > 260 characters; duplicate files; dormant(?) accounts not used in forever; how much ram is installed in "joe's" workstation...things like that which are "all over the map", so to speak.

    So one of the first "real" tasks I decided to do was pull a listing of all active users in my OU and the security/distribution groups they belong to. Since I already have a fresh list of all active accounts in my OU, I pipe the user names from that list into the script, and then output the results to a txt file I can open in Excel/Access/etc...

    When I test a new script like this one, I only use a list of 8 people (my office mates) because I'm more concerned with getting the script to pull the right data than getting the data ASAP

    Question 1 – Is it true that piping an already existing list of active users to the script places less of a load on the server than querying for active accounts and then piping those results into the script to pull security groups?

    I'm just wondering because I do not mind if the script takes a longer time to run, as long as I'm not stressing the servers.

    Question 2 – Of the following two scripts, which seems less stressing to the server?

    (I have actually came up with two similar ways to pull the user's Security/Distribution group information)

    My first script (well both of them actually) look(s) like grabage compared to most, but it's listed below]

    $userlist = Get-Content c:\inputfiles\Userlist3.txt
    Foreach($User in $Userlist) {
    $username = (Get-ADUser $user -Property Name)
    $Gname = Get-QADUser -SamAccountName $user | select LogonName,@{Name='MemberOf';Expression={ (Get-QADMemberOf $_ | Select-Object -Expand Name ) -join ';' }}
    $str1 = $user+$Gname
    Add-Content c:\outputfiles\UserGroups.txt -value $str1 }

    I get results like:

    joe.murphy@{LogonName=joe.murphy; MemberOf=Domain Users;Group2;Group3;Group4;Group5;Group6;Group7;Group8;Group9}
    elizabeth.montgomery@{LogonName=elizabeth.montgomery; MemberOf=Domain Users;Group2;Group3;Group4;Group5;Group6}
    and so on...

    My second script looks like]
    $Userlist = Get-Content c:\inputfiles\userlist3.txt
    foreach($user in $userlist) {
    $strname=(Get-QADUser -samaccountname $user |select name)
    $strname=$strname-replace'@{Name=',''
    $strname=$strname-replace'}',''
    $strGRP=get-qaduser $strname | get-qadmemberof | select Name
    $strGC=($strGRP).count
    $strGRP=$strGRP-replace'@{Name=',','
    $strGRP=$strGRP-replace'}',''
    $strDONE=$strname+','+$strGC+$strGRP
    Add-Content c:\outputfiles\UserGroups.txt -value $strdone
    }

    Its output is a little different because I'm manipulating the string data a fair amount before writing to a file, and I'm totalling how many groups each member is assigned

    agness.morehead,10,Domain Users,Group2,Group3,Group4,Group5,Group6,Group7,Group8,Group9,Group10
    dick.york,8,Domain Users,Group2,Group3,Group4,Group5,Group6,Group7,Group8
    and so on...

    It's cleaner output, but I am not sure if the replaces are occuring locally on my workstation or not.

    I know this was done with the quest plugin, which seems to use different names for identifying fields. I'm actually learning the MS PS commands as well as the quest ones simultaneously, because why be confused in just one language when you can be confused in multiple dialects of that same language so you know absolutely squat about anything?

    I may be a bit paranoid about the server load, I admit. I've only run this against a list of the 8 people in my office, and it runs fine. Takes about a second or 1.25sec for each record to be written.

    The thing is, I have about 6000 people in my OU so I don't want to crash the server...

    Question 3 – If there is a possibility that it is placing stress on the servers, Is there a way I could possibly add a half a second increment to slow down the rate of requests?

    Edited to add: The time taken to return the information may seem long, but my servers are located about 1500 miles away.

    by ArtB0514 at 2013-03-13 10:45:03

    It is highly unlikely that you are putting any significant stress on the remote server because network latency will slow the query rate enough so that there will be minimum impact.

    However, if you are still concerned, you can reduce the load on the server significantly by collecting all the data that you want with a single query instead of multiples. For example, this should give you all the information that you want with a single call to Get-QADUser:

    $Userlist = Get-Content c:\inputfiles\userlist3.txt
    foreach($user in $userlist) {
    $U = Get-QADUser -samaccountname $user
    $strGC=($U.AllMemberOf).count
    $strGRP=($U.AllMemberOf | foreach {($_.Split(','))[0].Substring(3)) -Join ","
    $strDONE="$($User.Name),$strGC,$strGRP"
    Add-Content c:\outputfiles\UserGroups.txt -value $strdone
    }

    by notarat at 2013-03-13 13:15:54

    [quote="ArtB0514"]It is highly unlikely that you are putting any significant stress on the remote server because network latency will slow the query rate enough so that there will be minimum impact.

    However, if you are still concerned, you can reduce the load on the server significantly by collecting all the data that you want with a single query instead of multiples. For example, this should give you all the information that you want with a single call to Get-QADUser:

    $Userlist = Get-Content c:\inputfiles\userlist3.txt
    foreach($user in $userlist) {
    $U = Get-QADUser -samaccountname $user
    $strGC=($U.AllMemberOf).count
    $strGRP=($U.AllMemberOf | foreach {($_.Split(','))[0].Substring(3)) -Join ","
    $strDONE="$($User.Name),$strGC,$strGRP"
    Add-Content c:\outputfiles\UserGroups.txt -value $strdone
    }
    [/quote]

    Thanks for the response!

    I ran your example of the code and received some errors I listed below.

    [list]Missing closing '}' in statement block.
    At line:5 char:71

    Missing closing ')' in expression.
    At line:6 char:5

    Unexpected token 'strDONE' in expression or statement.
    At line:6 char:5

    Unexpected token '=' in expression or statement.
    At line:6 char:13

    Unexpected token '$($User.Name),$strGC,$strGRP' in expression or statement.
    At line:6 char][/list]

    I started going through the code to see what I could do with my limited experience.

    I deleted everything after

    $U=Get-QADUser -samaccountname $user
    (added this bit)Write-Host $u }

    That ran fine so I went to the next section

    $strGC=($U.AllMemberOf).count
    Write-Host $strGC }

    Now I'm getting the usernames and the number of groups to which each is assigned

    Moving onto the part

    $strGRP=($U.AllMemberOf | foreach {($_.Split(','))[0].Substring(3))) -Join ","

    will probably take me some time to troubleshoot, but I'm working on it. Thanks again for the response! I'm hoping I'll figure out the more cryptic section today and will let you know if I need additional "translation" 😉

    by ArtB0514 at 2013-03-13 13:38:51

    Sorry about the error; I'm surprised that I didn't see it in the IDE. Yes, line 5 does have a ")" where it should have a "}". The correct line is:
    $strGRP=($U.AllMemberOf | foreach {($_.Split(','))[0].Substring(3)}) -Join ","
    Decomposing it:
    $U.AllMemberof is the list of distinguished names of all groups that the user belongs to. We take each of them and split them on the comma separating the elements of the DN: "$_.Split(',')". This creates an array from which we choose only the first element: "($_.Split(','))[0]". The next element ".Substring(3)" removes the "CN=" from the front of the name. Finally, we combine all of the group names into a single string separated by commas.

    by notarat at 2013-03-13 13:43:58

    Art,

    I was writing a follow-up post and couldn't post it because you already responded. (nice board feature!)

    Thanks very much for the code and translation into language even I can understand!

    by notarat at 2013-03-14 09:43:28

    [quote="ArtB0514"]Sorry about the error; I'm surprised that I didn't see it in the IDE. Yes, line 5 does have a ")" where it should have a "}". The correct line is:
    $strGRP=($U.AllMemberOf | foreach {($_.Split(','))[0].Substring(3)}) -Join ","
    Decomposing it:
    $U.AllMemberof is the list of distinguished names of all groups that the user belongs to. We take each of them and split them on the comma separating the elements of the DN: "$_.Split(',')". This creates an array from which we choose only the first element: "($_.Split(','))[0]". The next element ".Substring(3)" removes the "CN=" from the front of the name. Finally, we combine all of the group names into a single string separated by commas.[/quote]

    Art,

    Wanted to follow up to say I made some mods to the code you supplied in order to pull the Computer and Computer Security Group/Application Distribution Groups, and it's working great, so I thought I'd post it here in case someone finds this thread and your excellent post.

    # PURPOSE: Scan Active Directory for each computer in the input file and
    # record the ComputerName, Number of App/Sec Groups to which
    # the Computer is Assigned/Associated, and list all Groups,
    # even those it is associated to via indirect group membership
    # PROG. LOGIC: Read Input File. For Each Computer Name, store Name to $C,
    # store Total of all group memberships to $STRGC,
    # store Group Names to $STRGRP after removing extraneous data
    # combine values into $STRDONE and write to outputfile.
    $computerlist = Get-Content c:\inputfiles\computers.txt
    foreach($computer in $computerlist) {
    $C=Get-QADcomputer -identity $computer -IncludeAllProperties
    $strGC=($C.AllMemberOf).count
    $strGRP=($C.AllMemberOf | foreach {($_.Split(','))[0].Substring(3)}) -Join ","
    $strDONE="$C,$strGC,$strGRP"
    Add-Content c:\outputfiles\ComputersandGroups.txt -value $strdone
    }

You must be logged in to reply to this topic.