How to find Active Directory User Accounts created in the last week

This is a script to find the list of Active Directory User Accounts created in, say, the last week, or even in the last year. The script exports the output to a CSV file, saves it to your desktop, and then opens the CSV file for you. 
In the script we first need to import Active Directory Module for PowerShell (installing RSAT tools on your machine will
Thanks to Aman, here is the script:
  1. <# 
  2.     Author  : Aman Dhally 
  3.     Email    : amandhally@gmail.com 
  4.     Date    : 16August2012 
  5.     Script & Purpose    : Created AD user Within Date  — to find new AD users created With-In a week 
  6.     website : http://www.amandhally.net 
  7.     twitter : https://twitter.com/#!/AmanDhally  
  8.                /^(o.o)^\  V.1 
  9.  #> 
  10.  
  11. # Import Active Directory Module, i.e. first install the RSAT Tools
  12. # http://www.amandhally.net/2012/02/13/automate-server-administration-tools/&nbsp; 
  13.     cls 
  14.     “`n” 
  15.     Write-Host ” ==> Importing Active Direcotry Module.” -ForegroundColor ‘Green’  
  16.     Import-Module -Name ActiveDirectory  
  17.  
  18. # Here we give a date 7 days before 
  19. # for 15 days, use $week = (Get-Date).AddDays(-15) 
  20. # for a month, user $week = (Get-Date).AddDays(-30) 
  21. # for a year, you can use $week = (Get-Date).AddDays(-365) 
  22.     Write-Host ” ==> Setting Date Period defined by you.” -ForegroundColor ‘Yellow’ 
  23.     $week = (Get-Date).AddDays(7) 
  24.  
  25. # Save the CSV File on users Desktop 
  26.     Write-Host ” ==> Setting file path.” -ForegroundColor ‘Magenta’ 
  27.     $filepath = “$env:USERPROFILE\desktop” 
  28.  
  29. # run on all users and save the output to csv file and the file will be saved on your desktop 
  30.   Write-Host ” ==> Running your query on all AD users.” -ForegroundColor ‘Cyan’ 
  31.     “`n” 
  32.     Get-ADUser Filter * -Properties * | ` 
  33.     where { $_.whenCreated -ge $week } | select Name,whenCreated ` 
  34.     Export-Csv -Path “$filepath\NewAdusers.csv” 
  35.  
  36. #Now open the file 
  37.     Write-Host ” ==> Opening NewAdusers.csv file.” -ForegroundColor ‘Green’ 
  38.     Invoke-Expression “$filepath\NewAdusers.csv” 
  39.  
  40. #End of the script  
  41.  ################################################### 
  42. # quote  
  43. “`n” 
  44. “`n” 
  45. Write-Host   Quote of the script   -ForegroundColor ‘Red’ 
  46. Write-Host   Give up your selfishness, and you shall find peace,” -ForegroundColor ‘Yellow’ 
  47. write-host   like water mingling with water, you shall merge in absorption. SGGS” -ForegroundColor ‘Magenta’ 
  48. “`n” 
  49. ### 

Firewall Problems When Enabling Remoting

http://powershell.com/cs/blogs/tips/archive/2012/10/24/firewall-problems-when-enabling-remoting.aspx

 

Enabling PowerShell Remoting is a simple thing: open an elevated PowerShell console and type:

PS> Enable-PSRemoting -Force

There are two types of exceptions you may encounter. One is complaining about public network adapters. If that’s the case, open “Network and Sharing Center”, click on “Change adapter settings” in the left column of the dialog window and temporarily disable public adapters. Often, these are virtual adapters from some sort of virtualization solution. Or, in PowerShell v3, use the new parameter -SkipNetworkProfileCheck.

The other type of exception complains about not being able to check the Firewall status. The reason for this is an error in the Firewall binaries that can occur when you are using a language pack. So if your UI is let’s say German but your system is English (or vice versa), then this error may occur. To work around it, log on with a user that uses the native system UI language.


Don’t forget to set the following if you want to connect to remote computers using an IP address or outside a domain:

PS> Set-Item WSMan:\localhost\client\trustedhosts * -Force

Export-CSV -Append #powershell

Export-CSV -Append

 

Here’s the solution for those who need to append rows to existing CSV files (andcannot do that): I have just used PowerShell 2.0 code snippets to create a proxy cmdlet – function which wraps standard Export-CSV cmdlet but adds handling of the-Append parameter.

So you can do something like:

Get-Process | Export-Csv -Path 'c:\Temp\processes.csv' -Append -Delimiter ';'

As you can see, other parameters – such as Delimiter – still function as well. If the file does not exist – the cmdlet will essentially ignore -Append and create the file as normal. If you specify -Append and the file is present, the function will turn the objects into CSV strings, remove the first row with the property names and append to the existing file.

For your convenience, I have posted the source code to PoshCode. Here’s it is as well for those interested:

#Requires -Version 2.0

<#
  This Export-CSV behaves exactly like native Export-CSV
  However it has one optional switch -Append
  Which lets you append new data to existing CSV file: e.g.
  Get-Process | Select ProcessName, CPU | Export-CSV processes.csv -Append
  
  For details, see

http://dmitrysotnikov.wordpress.com/2010/01/19/export-csv-append/

  (c) Dmitry Sotnikov  
#>

function Export-CSV {
[CmdletBinding(DefaultParameterSetName='Delimiter',
  SupportsShouldProcess=$true, ConfirmImpact='Medium')]
param(
 [Parameter(Mandatory=$true, ValueFromPipeline=$true,
           ValueFromPipelineByPropertyName=$true)]
 [System.Management.Automation.PSObject]
 ${InputObject},

 [Parameter(Mandatory=$true, Position=0)]
 [Alias('PSPath')]
 [System.String]
 ${Path},
 
 #region -Append (added by Dmitry Sotnikov)
 [Switch]
 ${Append},
 #endregion 

 [Switch]
 ${Force},

 [Switch]
 ${NoClobber},

 [ValidateSet('Unicode','UTF7','UTF8','ASCII','UTF32',
                  'BigEndianUnicode','Default','OEM')]
 [System.String]
 ${Encoding},

 [Parameter(ParameterSetName='Delimiter', Position=1)]
 [ValidateNotNull()]
 [System.Char]
 ${Delimiter},

 [Parameter(ParameterSetName='UseCulture')]
 [Switch]
 ${UseCulture},

 [Alias('NTI')]
 [Switch]
 ${NoTypeInformation})

begin
{
 # This variable will tell us whether we actually need to append
 # to existing file
 $AppendMode = $false
 
 try {
  $outBuffer = $null
  if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
  {
      $PSBoundParameters['OutBuffer'] = 1
  }
  $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Export-Csv',
    [System.Management.Automation.CommandTypes]::Cmdlet)
        
        
 #String variable to become the target command line
 $scriptCmdPipeline = ''

 # Add new parameter handling
 #region Dmitry: Process and remove the Append parameter if it is present
 if ($Append) {
  
  $PSBoundParameters.Remove('Append') | Out-Null
    
  if ($Path) {
   if (Test-Path $Path) {        
    # Need to construct new command line
    $AppendMode = $true
    
    if ($Encoding.Length -eq 0) {
     # ASCII is default encoding for Export-CSV
     $Encoding = 'ASCII'
    }
    
    # For Append we use ConvertTo-CSV instead of Export
    $scriptCmdPipeline += 'ConvertTo-Csv -NoTypeInformation '
    
    # Inherit other CSV convertion parameters
    if ( $UseCulture ) {
     $scriptCmdPipeline += ' -UseCulture '
    }
    if ( $Delimiter ) {
     $scriptCmdPipeline += " -Delimiter '$Delimiter' "
    } 
    
    # Skip the first line (the one with the property names) 
    $scriptCmdPipeline += ' | Foreach-Object {$start=$true}'
    $scriptCmdPipeline += '{if ($start) {$start=$false} else {$_}} '
    
    # Add file output
    $scriptCmdPipeline += " | Out-File -FilePath '$Path'"
    $scriptCmdPipeline += " -Encoding '$Encoding' -Append "
    
    if ($Force) {
     $scriptCmdPipeline += ' -Force'
    }

    if ($NoClobber) {
     $scriptCmdPipeline += ' -NoClobber'
    }   
   }
  }
 } 
  

  
 $scriptCmd = {& $wrappedCmd @PSBoundParameters }
 
 if ( $AppendMode ) {
  # redefine command line
  $scriptCmd = $ExecutionContext.InvokeCommand.NewScriptBlock(
      $scriptCmdPipeline
    )
 } else {
  # execute Export-CSV as we got it because
  # either -Append is missing or file does not exist
  $scriptCmd = $ExecutionContext.InvokeCommand.NewScriptBlock(
      [string]$scriptCmd
    )
 }

 # standard pipeline initialization
 $steppablePipeline = $scriptCmd.GetSteppablePipeline(
        $myInvocation.CommandOrigin)
 $steppablePipeline.Begin($PSCmdlet)
 
 } catch {
   throw
 }
    
}

process
{
  try {
      $steppablePipeline.Process($_)
  } catch {
      throw
  }
}

end
{
  try {
      $steppablePipeline.End()
  } catch {
      throw
  }
}
<#

.ForwardHelpTargetName Export-Csv
.ForwardHelpCategory Cmdlet

#>

}

Hope this helps! ;)

 

 

20 Responses to “Export-CSV -Append”

  1. Jason ArcherJanuary 19, 2010 at 10:25 pm

    Reader beware, you can have some problems if you append a different kind of object (or number of columns) than what is already in the file.

    • Dmitry SotnikovJanuary 20, 2010 at 7:02 am

      Yes, good point Jason! In my code I am NOT checking whether the property names are the same. Or that delimiter is the same. Or that encoding is the same. And so on. It is up to user to make sure that appended data matches the original one.

      • TimAugust 4, 2011 at 2:50 pm

        How exactly would one go about formatting data to match the original? For example:

        Data in csv is from SMO dataFile object containing server, dbname, size, usedSpace, freespace.

        I want to append a TOTAL row for each instance after all of the databases have been appended. I have tried building my own object/string and appending it to the csv, but I can’t seem to get it right. Any help would be much appreciated.

        Here is what I have tried:
        $totalString = “@{Server=$servername; dbname=$total; Size=$totalsize; UsedSpace=$totalUsed; FreeSpace=$totalFree}”;
        (above, with and without, @, {}, and quotes)

        $totalString = @”
        Server : $servername
        dbname : $total
        Size : $totalsize
        UsedSpace : $totalUsed
        FreeSpace : $totalFree
        “@

        $totalstring | export-csv c:\test.csv -append;

        Thanks,
        TIm

  2. John HuberFebruary 4, 2011 at 4:49 pm

    Thanks, I am an admin, who is not a good coder. This is a great help for me and makes my life a lot easier.

    Many Thanks

  3. Alvin MagpayoApril 7, 2011 at 11:07 pm

    Hi,
    Im quite new with powershell and this post regarding Export-CSV with append is very helpful to complete my automated script reports.

    I just don’t know how to use it. What do you mean with “Add this function to your profile to make Export-CSV cmdlet handle -Append parameter” in the poshcode.org?

    I just need to make it work and use the -Append of Export-CSV and time is killing me due to my deadline.

    Thanks in advance.

  4. Alvin MagpayoApril 9, 2011 at 8:09 am

    Thanks. It worked! I was able to do it and had the -Append on Export-CSV.

    One more question though, What if I want to make sure that this profile will be used all the time? My script will run as a scheduled job and placed on different server.

    Is there a way that I can call the same profile just to make sure that the code will be executed, or is it possible that I can include that at the top of the code as one of the validation process?

    Thanks for the help. :D

    Alvin.

  5. Alvin MagpayoApril 9, 2011 at 12:20 pm

    ei,
    I got it working. Thanks. Appreciate the help. :)

    Alvin

  6. JamieMay 5, 2011 at 9:33 pm

    I am having trouble using this script. When I use the command, I get an error saying “The varialbe ‘$UseCulture’ cannot be retrieved because it has not been set”. The error references line 96 and char 21. Please help.

    Thanks,
    Jamie

    • Dmitry SotnikovMay 5, 2011 at 11:02 pm

      Jamie,

      Looks like you have strict mode on, and this somehow does not like the parameter declarations of the function.

      One easy workaround that I see is to simply add Set-StrictMode -Off to the biginning of the script… If this is unacceptable, you’ll need to figure out how to make the PowerShell parser consider the parameters ok to use in the script – let me know if you manage to do that.

      Dmitry

  7. Chad MillerMay 21, 2011 at 2:10 am

    Dimitry

    I’m wondering if you can help me understand this piece of code in from your script (modified slightly to illustrate an example):

    get-psdrive | foreach-object {$start=$true} {if ($start) {$start=$false} else {$_}}

    I understand the point–skip first row and it works perfectly. I’ve seen scriptblocks before, but this one looks odd.

    The first block is the foreach-object block and the second block, well I don’t understand how the pipeline is able to continue to pipe objects.

  8. Chad MillerMay 21, 2011 at 8:11 pm

    My previous question was answered via Twitter by Bartek

    “Looks like -begin and -process blocks. So the {$start = $true} is run only once, before obj arrive”

    Sure enough get-help foreach-object mentions these params, but the documentation incorrectly states they are named params.

  9. JCochranDecember 8, 2011 at 9:12 pm

    Am I missing something? While I greatly appreciate this code, and I could not code myself out of a brown paper bag, isn’t this an excessive amount of code to simply append a file? I mean that with all due respect and I am more than likely missing something, but this seems counter to the simplicity of the intended nature of PowerShell. I am one person that is finding PowerShell to be powerful, but not all that simple. I rarely have time to code and read and it seems like a significant amount of time is required to learn PowerShell to this degree. Maybe I’m dumb? I dunno… :p

  10. Daniel RymerJanuary 25, 2012 at 2:27 pm

    Code works great. I tried writing my own using 2 additional temp files, which was far shorter, but kept ending up with blank lines I couldn’t seem to remove. I used this code and the file came out perfect! Thanks!

PowerShell script in a .bat file

PowerShell script in a .bat file

How do you put PowerShell code into a batch/cmd file without having to also have a separate .ps1 file? (If you can have an external .ps1 file – you just invoke powershell.exe and supply the path to the script file as parameter.)

I got this question recently from one of our field guys and thought I would blog about the trick publicly.

The problem is that PowerShell syntax can obviously have elements that .bat files cannot stand, and that you cannot pass multiline script as powershell.exe parameter.

There are actually a couple of ways to do so:

1. Encode the script:

As Bruce points here PowerShell has the -EncodedCommand parameter, which lets you pass any PowerShell code as base-64-encoded string.

So if you have some sort of script, like this:

#iterate numbers 1 through 10
1..10 | foreach-object {
# just output them
"Current output:"
$_
}

You simply (in PowerShell command-line or script) put it in curcly brackets and assign (as scriptblock) to a variable:

$code = {
    #iterate numbers 1 through 10
    1..10 | foreach-object {
    # just output them
    "Current output:"
    $_
    }
}

Then use this PowerShell command to get the encoded version:

[convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($code))

Then copy/paste the output of the command to your batch file:

powershell.exe -EncodedCommand DQAKAAkAIwBpAHQAZQByAGEAdABlACAAbgB1AG0AYgBlAHIAcwAgADEAIAB0AGgAcgBvAHUAZwBoACAAMQAwAA0ACgAJADEALgAuADEAMAAgAHwAIABmAG8AcgBlAGEAYwBoAC0AbwBiAGoAZQBjAHQAIAB7AA0ACgAJACMAIABqAHUAcwB0ACAAbwB1AHQAcAB1AHQAIAB0AG
gAZQBtAA0ACgAJACIAQwB1AHIAcgBlAG4AdAAgAG8AdQB0AHAAdQB0ADoAIgANAAoACQAkAF8ADQAKAAkAfQANAAoA

2. Keep the code as PowerShell but turn it to a string:

If the first approach for whatever reason does not work for you (e.g. you care about readability), you can try to flatten the script and pass it as a string:

  1. Take the PowerShell script.
  2. Remove all the comments ( everything that starts with #).
  3. Put ; at the end of each line.
  4. Remove all line breaks.
  5. Supply the string you get as the -command parameter for powershell.exe.

The reason for all of this is that powershell.exe (the executable which allows you to run any PowerShell code allows you to either start an external .ps1 script file (which often creates additional complexity of having to maintain and ship 2 files) or execute a single line of PowerShell code as the -command parameter. Hence the requirement to flatten the script and turn something like this:

#iterate numbers 1 through 10
1..10 | foreach-object {
# just output them
"Current output:"
$_
}

into:

powershell.exe -command '1..10 | foreach-object { "Current output:"; $_; }'

 

See also this blog post by MoW on making PowerShell pass its exit code to command files.

How to Schedule a PowerShell Script

 

How to Schedule a PowerShell Script

..assuming that you are running PowerShell 2.0..

1. Get your script ready

Surprising as it might sound, your script might actually not be ready to run in a scheduled task as is. This happens if it uses cmdlets from a particular PowerShell module or snapin, and it worked for you interactively because you used a specialized shell (e.g. Exchange Management Shell) or a tool like PowerGUI Script Editor which loads the modules for you.

If you indeed are using using any non-default cmdlets, simply add Add-PSSnapin or Import-Module to the beginning of the script. For example:

Add-PSSnapin Quest.ActiveRoles.ADManagement

2. Schedule the task

To schedule a task simply start Windows Task Scheduler and schedule powershell.exe executable passing the script execution command as a parameter. The -Fileparameter is the default one so simply specifying the script path as the argument would work in a lot of cases:

You can find powershell.exe in your system32\WindowsPowerShell\v1.0 folder.

4. Report task success or failure

If you want your script to report success or failure (or some sort of other numerical result) simply use the exit keyword in the script to pass the value, e.g.:

exit 4

Then your Windows Task Scheduler will show the value in the Last Run Result (you might need to hit F5 to refresh the column in the task scheduler):

3. Passing parameters

If you need to pass parameters things get a little trickier. Say, you have a script which adds two numbers:

param($a=2, $b=2)
"Advanced calculations ahead"
exit $a + $b

To pass the numbers as parameters, you would want to use powershell.exe -Command instead of powershell.exe -File. This -Command argument will then have the script invocation operator &, path to the script, and the parameters. E.g.:

ProgramC:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Add argument (optional)-Command "& c:\scripts\hello.ps1 -a 2 -b 3"

If you want to also get your exit code from the script, you would need to re-transmit that by adding exit $LASTEXITCODE to the command (I learnt this tip from MoW). E.g.

ProgramC:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Add argument (optional)-Command "& c:\scripts\hello.ps1 -a 2 -b 3; exit $LASTEXITCODE"

5. Run x86 PowerShell on x64 Windows

On 64-bit versions of Windows you actually have both 64-bit and 32-bit versions of PowerShell. In most cases you don’t care but in some cases (e.g. specific COM objects being used) you might need specifically a 32-bit version. To get that to run, simply pick the proper executable when you schedule the task:

Regular PowerShell (64-bit version on 64-bit Windows):%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe

32-bit PowerShell (x86):%SystemRoot%\syswow64\WindowsPowerShell\v1.0\powershell.exe

6. Other options

To learn about all parameters PowerShell executable has simply run it with /? option (from either cmd.exe or a PowerShell session).

I normally use -noprofile to make sure that nothing in the PowerShell profile interferes with the task.

Also, if your Execution Policy does not allow running scripts the -ExecutionPolicy parameter comes handy allowing you to make an exception just for this task. E.g.:

c:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -File c:\scripts\hello.ps1 -ExecutionPolicy RemoteSigned

Here are some other parameters provided by PowerShell:

-PSConsoleFile
    Loads the specified Windows PowerShell console file. To create a console
    file, use Export-Console in Windows PowerShell.

I guess you could use that is you want the exact environment you have in the predefined shell from Exchange, AD, or SQL. E.g.: PowerShell -PSConsoleFile SqlSnapIn.Psc1

-Version
    Starts the specified version of Windows PowerShell.

I don’t think this one actually works.

-NoLogo
Hides the copyright banner at startup.

Not really relevant for scheduled tasks, imho…

-NoExit
    Does not exit after running startup commands.

Might be useful for troubleshooting.

-Sta
    Start the shell using a single-threaded apartment.

If your script needs STA mode (if you don’t know what this is – most likely you don’t need this. ;) )

-NonInteractive
    Does not present an interactive prompt to the user.

Not really relevant for scheduled tasks, imho…

-InputFormat
    Describes the format of data sent to Windows PowerShell. Valid values are
    "Text" (text strings) or "XML" (serialized CLIXML format).

-OutputFormat
    Determines how output from Windows PowerShell is formatted. Valid values
    are "Text" (text strings) or "XML" (serialized CLIXML format).

Not sure how I would use those… Here’s one example of how -InputFormat nonecan help fix issues with PowerShell becoming unresponsive when waiting for input.

-WindowStyle
    Sets the window style to Normal, Minimized, Maximized or Hidden.

Unfortunately, I could not make this work. I tried to use -WindowStyle Hidden to avoid the PowerShell console window popping up during task execution but with no luck.

-EncodedCommand
    Accepts a base-64-encoded string version of a command. Use this parameter
    to submit commands to Windows PowerShell that require complex quotation
    marks or curly braces.

    # To use the -EncodedCommand parameter:
    $command = 'dir "c:\program files" '
    $bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
    $encodedCommand = [Convert]::ToBase64String($bytes)
    powershell.exe -encodedCommand $encodedCommand

Can be useful when having to pass advanced expressions and getting issues with parser.

 

 

 

Here are a few more articles:

http://www.searchmarked.com/windows/how-to-schedule-a-windows-powershell-script.php

http://exchangeshare.wordpress.com/2008/12/08/how-to-schedule-powershell-script-for-an-exchange-task/

http://www.vistax64.com/powershell/23314-how-schedule-powershell-script.html

http://www.windowsitpro.com/blogs/PowerShellwithaPurpose/tabid/2248/entryid/72376/How-to-Schedule-PowerShell-Scripts.aspx

 

Working with Active Directory using PowerShell ADSI adapter

 

Working with Active Directory using PowerShell ADSI adapter (en-US)

Introduction

PowerShell is very useful for automating Active Directory. It allows to quickly and relatively easy automate mundane actions or perform same operations with many objects. PowerShell provides very broad set of methods to work with Active Directory. There is some of them:In this article provided examples of using ADSI adapter and .NET classes. This is not an easiest method, but sometimes you just need it. For example if you working in organization that uses old operating system for domain controllers (not 2008R2+), and you cannot install any additional software on controllers or servers, but need to work with Active Directory in your script.

Receiving an object representation of Active Directory object.

This method requires knowledge of object's LDAP path.
001
$Object = [adsi]'LDAP://CN=Notebook1,OU=Computers,DC=consoso,DC=com'

Searching for an object in Active Directory.

001 002 003 004
$Searcher = New-Object DirectoryServices.DirectorySearcher $Searcher.Filter = '(&(objectCategory=person)(anr=gusev))' $Searcher.SearchRoot = 'LDAP://OU=Laptops,OU=Computers,DC=consoso,DC=com' $Searcher.FindAll()
Filter property of the Searcher object uses standard LDAP query syntax  . You can also use FindOne() method to receive just first found object.

Setting "Password never expire" attribute on user object

This property unlike many other properties of AD object are contained in bitmask attribute UserAccountControl (not related in any way with User Account Control feature of Windows). To set it you need to retrieve current value of this attribute and use binary OR operation (-bor) to calculate new value. 
001 002 003 004
$User = [ADSI]"LDAP://cn=Gusev,ou=Users,ou=Lab,dc=contoso,dc=com" $UAC = $User.UserAccountControl[0] -bor 65536 $User.Put("userAccountControl",$UAC) $User.SetInfo()
  

Get direct AD group membership information

Members of the group are contained as Distinguished Names in Member array property of a group. To get objects representing the members one need to get contents of this property and create ADSI objects from them.
001 002
$Group = [ADSI]"LDAP://cn=Domain Admins,cn=Users,dc=Contoso,dc=Com" $Members = $Group.Member | ForEach-Object {[ADSI]"LDAP://$_"}
  Same way, groups in which AD object is directly included are contained in its MemberOf property. 
001 002
$User = [ADSI]"LDAP://cn=Administrator,cn=Users,dc=Contoso,dc=Com" $Groups = $User.MemberOf | ForEach-Object {[ADSI]"LDAP://$_"}
  

Get AD object class name

Primary class of AD object are contained in Class property, but there is also ObjectClass property that contains all classes to which object is belong.
PS C:\> $Object = [ADSI]"LDAP://cn=Administrator,cn=Users,dc=Contoso,dc=Com"
PS C:\> $Object.class
user
PS C:\> $Object.objectclass
top
person
organizationalPerson
user