How to get object type/identifier? - powershell

In PowerShell, when I work with Active Directory specifically, often I'll compile an object containing a list of groups of people usually with $x = get-adgroup -filter {name -like "*"} | select-object name which gives me a list with a header or object type name:
name
----------
name1
name2
name3
How can I access the name header of the object or even change it to something else?
Can it be done similarly to the way I would access the string of the first entry like $x[0].name?
Further, is there a more generic way to access the string associated with an arbitrary entry?
I'm being asked to a lot of "programming" in PowerShell related to AD so any resources you can provide to help me would be greatly appreciated.

If you want to change the name you can create an expression for it in your select block:
get-adgroup -filter {name -like "*"} | select-object #{Name="WhatYouWannaCallIt";Expression={$_.Name}}
This would now give you:
WhatYouWannaCallIt
------------------
name1
name2
name3

The two things that I think you are asking for is a programmatic way to determine the name of a given property in an object.
(get-aduser $user | select name).psobject.properties
MemberType : NoteProperty
IsSettable : True
IsGettable : True
Value : Matt
TypeNameOfValue : System.String
Name : name
IsInstance : True
The Name property of .psobject.properties contains most of this information and I think you might be looking for.
Was going to answer the second part with what Arco444 just said about using select-object

Do you mean:
$x = get-adgroup -filter {name -like "*"}
$x.name
or
(get-adgroup -filter {name -like "*"}).name

Related

Powershell - Issues to test a value in a list

I have a 2 variables:
$Listgivenname = Get-aduser -filter * | Select-Object givenname
$Usergivenname = "Tom"
Actually, Tom is in $Listgivenname, so I decided to make an if statement like:
If($Listgivenname -contains $Usergivenname) {Write-Host "blablabla"}
But actually this command outputs false, even with $Usergivenname -in $Listgivenname.
The weird part comes when I choose to manually write the list in $Listgivenname, like "Tom", "Jerry". It actually works, so I believe there's a thing that I need to understand about a command witch I assign to a variable.
Get-aduser -filter * | Select-Object givenname doesn't seem to work like a manually written list.
I don't ask for solutions but I'm trying to understand why this happens.
try add -ExpandProperty (to get the values of each object):
$Listgivenname = Get-aduser -filter * | Select-Object -ExpandProperty givenname

Get AD user properties from Active Directory

I am trying to filter the values of a property in Active Directory.
I tried:
Get-ADUser -filter * -Properties physicalDeliveryOfficeName | Where-Object (($_.physicalDeliveryOfficeName -like "NICE")) | Select-Object physicalDeliveryOfficeName, name
Get-ADUser -filter * -Properties physicalDeliveryOfficeName | Select-Object physicalDeliveryOfficeName, name | Where-Object (($_.physicalDeliveryOfficeName -like "NICE"))
I did not get any errors, but no results either.
I searched all users with physicaldeliverofficename is (myvalue). I would like to display name and office.
You have a syntax problem:
The Where-Object's (positionally implied) -FilterScript parameter expects a script block argument - { ... } - not a parenthesized expression ((...)).[1]
Therefore:
# Note the { ... } around the expression passed to Where-Object
Get-ADUser -Filter * -Properties physicalDeliveryOfficeName |
Where-Object { $_.physicalDeliveryOfficeName -eq "NICE" } # | ...
Note: Since "NICE" is a literal string rather than a wildcard pattern, I've used the -eq instead of the -like operator. If you doe need to find "NICE" as a substring, use something like -like "*NICE*" or, for case-sensitive matching, -clike "*NICE*", as Mathias R. Jessen suggests.
Note that you may alternatively use simplified syntax, which obviates the need for a script block and allows use of individual parameters (also note the absence of $_., which is implied):
Get-ADUser -Filter * -Properties physicalDeliveryOfficeName |
Where-Object physicalDeliveryOfficeName -eq "NICE" # | ...
Taking a step back:
Santiago Squarzon suggests performing the filtering at the source, by using Get-ADUser's -Filter or -LDAPFilter parameter, which is much more efficient; e.g.:
Get-ADUser -Filter 'physicalDeliveryOfficeName -eq "NICE"'
As an aside: There are many examples out there that use script-block syntax with -Filter (-Filter { ... }), but the -Filter parameter accepts a string and that string, even though it supports PowerShell-like syntax, is interpreted by the AD provider, so it's better to pass a string to begin with - see this answer for more information.
[1] If you use (...), the expression's value gets bound to the -Property parameter instead, and is therefore interpreted as a property name whose value - assuming such a property even exists - is interpreted as a Boolean that determines whether the input object at hand should be filtered in or not. If the expression doesn't evaluate to the name of a property that exists on an input object, $false is implied, and the input object is filtered out. In your case, this predictably resulted in no objects being filtered in and therefore no output.
The Select-Object cmdlet is used to select only the columns you want from a larger object or list.
For instance:
C:\git\Core> gsv Spooler | fl
Name : Spooler
DisplayName : Print Spooler
Status : Running
DependentServices : {Fax}
ServicesDependedOn : {RPCSS, http}
CanPauseAndContinue : False
CanShutdown : False
CanStop : True
ServiceType : Win32OwnProcess, InteractiveProcess
Get-Service returns Service Objects which have a lot of properties. If I only want certain ones, I'd use it like so:
C:\git\Core> gsv Spooler | Select Name,Status
Name : Spooler
Status : Running
You're using the cmdlet and probably discarding the columns which have the values you need. Run your one-liner again and remove the Select-Object cmdlet to see all of the columns availble, till you find the one that pertains to the Office.

PowerShell to check for missing ShadowCopies

Trying to check for SMB shares (DC's and member servers) that are missing Shadow Copies. Can't get the PowerShell filter just right.
This is the closest I've come. I'm still getting SYSVOL shares in the list.
Get-SmbShare -Special $False | FL Name,Path,ShadowCopy | Where-Object {(-not $_.ShadowCopy) -and ($_.Path -notlike "*sysvol*")}
I'm expecting the output to be like:
Name : test
Path : C:\test
ShadowCopy : False
You should never use the formatting cmdlet's in the middle of a pipeline. By using fl, you are essentially creating an array of strings. The where clause operates on those strings.
Most likely, you meant to do something like this
Get-SmbShare |
Where-Object {!($_.ShadowCopy) -and ($_.Path -notlike '*sysvol*')} |
fl name, path, shadowcopy

PowerShell Output Related to ADObject Properties

I'm trying to retain the Microsoft.ActiveDirectory.Management.ADAccount object when searching and specifying return outputs; however, when selecting the outputs, additional fields are populating. Questions:
Why is this is happening?
Is there a method, command, or filter to return only the specified parameters? (not the extra fields listed in the example below)
Is there a way to remove properties from the ADAccount Object? ($a in this example)
For the select method, is there a way to retain the original object formatting ? (I do not want a table and still need to reference the object later)
Running the following command:
$a = Get-ADUser $targetPerson -Properties Department, EmailAddress, Office, OfficePhone
returns:
Department : ****
DistinguishedName : CN=1111,OU=2222,OU=3333,OU=4444,DC=5555,DC=6666
EmailAddress : ****#mail.com
Enabled : ****
GivenName : ****
Name : ****
ObjectClass : user
ObjectGUID : ****
Office : ****
OfficePhone : ****
SamAccountName : ****
SID : ****
Surname : ****
UserPrincipalName : ****
Get-ADUser has a default set of properties it always returns, including for instance the distinguished name, the SID, and the account name. The parameter -Properties is for specifying which additional properties the cmdlet should return, because the default property set is just a small subset of all available properties.
To limit the output of Get-ADUser to a specific set of properties you need to pipe the output through Select-Object:
$props = 'Department', 'EmailAddress', 'Office', 'OfficePhone'
$a = Get-ADUser $targetPerson -Properties $props |
Select-Object $props
Of course that will turn the ADAccount object into a custom object (PSCustomObject), but I don't think there's a way around that.
The object Microsoft.ActiveDirectory.Management.ADAccount inherits members from the class it is created from. Here are some of the inherited members -
Name, ObjectClass, ObjectGUID, SID, and SamAccountName.
More about AD Object
I don't think you can create a Microsoft.ActiveDirectory.Management.ADAccount object with out those inherited members.
But if your project can accept a PSCustomObject then pipe $a to Select-object.
$a | Select-Object -Property Department, EmailAddress, Office, OfficePhone

Passing string in Get-ADUser filter parameter causes error - property not found in pscustomobject

I'm trying to create a new Active Directory user, but first I verify that the user doesn't exist already with Get-ADUser.
I import the user data from our HR department and build custom properties:
$newUsers = Import-Csv $csvFile |
Select-Object -Property #{n='EmpNum';e={$_.'Employee Number'}},
#{n='UPN';e={$_.'Email Address'}},
#{n='Alias';e={$_.'Email Address'.Split("#")[0]}} #### etc
When I loop through the objects from the CSV file, I use the UPN property to search for the user in Active Directory:
foreach ($newUser in $newUsers) {
$exists = Get-ADUser -Filter {UserPrincipalName -eq $newUser.UPN} -Properties * -Server $adServer -Credential $adCred
...
}
The filter causes an error:
Get-ADUser : Property: 'UPN' not found in object of type:
'System.Management.Automation.PSCustomObject'. At
C:\Users\bphillips.NEWHOPEOFIN\Dropbox\Powershell\NewHire\AddNewDSP.ps1:50
char:15
+ $exists = Get-ADUser -Filter {UserPrincipalName -eq $newUser.UPN} -Propertie ...
I've tried doing this: -Filter {UserPrincipalName -eq $("$newUser.UPN") but that doesn't help; I get another error
Get-ADUser : Cannot process argument because the value of argument
"path" is not valid. Change the value of the "path" argument and run
the operation again. At
C:\Users\bphillips.NEWHOPEOFIN\Dropbox\Powershell\NewHire\AddNewDSP.ps1:50
char:15
+ $exists = Get-ADUser -Filter {UserPrincipalName -eq $("$newUser.UPN")} -Prop ...
$newUser is a string, so I don't understand why it causes a problem. Hard-coding a UserPrincipalName like, "test#ourcompany.com" works, but the $newUser.UPN won't work.**
PS C:\> $newUser.UPN.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
and
PS C:\> $newUser.UPN | gm
TypeName: System.String
$newUser.UPN contains a valid string value
PS C:\> $newUser.UPN
ypope#ourcompany.net
What do I have to do to get $newUser.UPN to be recognized as a string for the filter parameter? What's going on that I don't understand?
The BNF for filter query strings does not allow expressions as the second operand in a comparison, only values (emphasis mine):
Syntax:
The following syntax uses Backus-Naur form to show how to use the PowerShell Expression Language for this parameter.
<filter> ::= "{" <FilterComponentList> "}"
<FilterComponentList> ::= <FilterComponent> | <FilterComponent> <JoinOperator> <FilterComponent> | <NotOperator> <FilterComponent>
<FilterComponent> ::= <attr> <FilterOperator> <value> | "(" <FilterComponent> ")"
<FilterOperator> ::= "-eq" | "-le" | "-ge" | "-ne" | "-lt" | "-gt"| "-approx" | "-bor" | "-band" | "-recursivematch" | "-like" | "-notlike"
<JoinOperator> ::= "-and" | "-or"
<NotOperator> ::= "-not"
<attr> ::= <PropertyName> | <LDAPDisplayName of the attribute>
<value>::= <compare this value with an <attr> by using the specified <FilterOperator>>
Put the value of the property you want to compare against in a variable and use that variable in the comparison. You may also want to define the filter as an actual string, if only for clarity (despite what it looks like the filter is not a scriptblock).
$upn = $newUser.UPN
$exists = Get-ADUser -Filter "UserPrincipalName -eq '$upn'" ...
Expressions can inside the filter block of a Get-ADUser but they need to be properly wrapped with quotes.
Get-ADUser -Filter "UserPrincipalName -eq '$($newUser.UPN)'"
Never use a script block ({ ... }) as the -Filter argument - the -Filter parameter's type is [string] - construct your filter as a string.
BenH's answer shows how to do that.
While seemingly convenient, using a script block only works in very limited scenarios and causes confusion when it doesn't work - such as when involving property access, as in this case.
For more information, see this answer of mine.