I am attempting to use the -ExpandProperty feature in PowerShell to stop the header appearing in the output and format the date without minutes and seconds. This is just to get the created date for an AD Object:
Get-ADComputer -Server $Server -Identity BlahBlah -Properties Created |
Select-Object -ExpandProperty #{Name="Created";Expression={$_.Created.ToString("yyyy-MM-dd")}}
This does not produce a result, only if I exclude the "-ExpandProperty" part will it produce the right date format BUT includes the header "Created" which I don't want.
Any ideas please?
I don't have access to an AD at the moment, but this could be what you are after
Updated
Get-ADComputer -Server $Server -Identity BlahBlah -Properties Created | Select-Object Created | ForEach-Object {$_.Created.ToString("yyyy-MM-dd")}
To complement LotPings' helpful answer, which offers effective solutions:
As for why your code didn't work:
While Select-Object's -Property parameter accepts hashtables that define calculated properties (such as in your code), the -ExpandProperty parameter only accepts a property name, as a string.
Therefore, your hashtable is simply stringified, resulting in string literal System.Collections.Hashtable, causing Select-Object to complain, given that there is no property by that name.
The purpose of -ExpandProperty is to output just a property value rather than a custom object with that property.
You therefore do not need a detour via Select-Object, and can just use the value-outputting script block - { $_.Created.ToString("yyyy-MM-dd") } - directly with ForEach-Object instead, as shown at the bottom of LotPings' answer.
However, there is an obscure feature that you forgo by using ForEach-Object: Select-Object allows combining -ExpandProperty with -Property, in which case the properties specified via -Property are added as NoteProperty members to the value of the property specified via -ExpandProperty:
PS> $val = [pscustomobject] #{ one = 'uno'; two = 2 } |
Select-Object -ExpandProperty one -Property two; $val; $val.two
uno
2
Note how the output string value, 'uno' has a copy of the input object's .two property attached to it.
To emulate that with ForEach requires more work:
PS> $val = [pscustomobject] #{ one = 'uno'; two = 2 } | ForEach-Object {
$_.one + '!' | Add-Member -PassThru two $_.two
}; $val; $val.two
uno!
2
In PowerShell there nearly always is more than one solution to a problem-
(Get-ADComputer -Server $Server -Identity BlahBlah -Properties Created |
Select-Object #{N="Created";E{$_.Created.ToString("yyyy-MM-dd")}} ).Created
or
Get-ADComputer -Server $Server -Identity BlahBlah -Properties Created |
Select-Object #{N="Created";E{$_.Created.ToString("yyyy-MM-dd")}} |
Select-Object -Expand Created
Parameter names can be shorted as long as they are uniquely identifiable and there are also shortcuts (uppercase letters) so -EA is -ErrorAction
A calculated property does IMO make no sense here as it is the only output, so this should do also:
Get-ADComputer -Server $Server -Identity BlahBlah -Properties Created |
ForEach-Object {$_.Created.ToString("yyyy-MM-dd")}
Related
My task include to filter all users names in group and subgroup in AD. Continue to filter the computers and show just those, which contains filtered names.The problem is, that description includes also other characters like space or "NEW".
My code:
foreach ($file in Get-ADGroupMember -Identity GroupName -Recursive) {Get-ADComputer -Filter 'Description -like $file.name' -Property Name,Description | Select -Property Name,Description}
It would be great to just add * or change -like to -include :D But...
My begginers question is: How to write the code to see all results, not just the ones which match exactly the $file.name?
Thank you for ur time!
Your initial problem was in the Filter you used. With the correct quoting and using the sub-expression operator $() that fixed it.
However, as promised in my comment, here's what I mean on how you can create a report of group members (both users, computers and if you like also subgroups).
Since all objects returned from the Get-ADGroupMember cmdlet have an .objectClass property, you can use that to determine what next Get-AD* cmdlet you can use.
Here, I'm capturing the collected objects output in the foreach() loop in a variable that you can show on screen, or save as Csv file you can open in Excel for instance.
$groupName = 'GroupName'
$result = foreach($adObject in (Get-ADGroupMember -Identity $groupName -Recursive)) {
# use the proper Get-AD* cmdlet depending on the type of object you have
switch ($adObject.objectClass) {
'user' {
$adObject | Get-ADUser -Properties Description | Select-Object Name, Description, #{Name = 'Type'; Expression = {'User'}}
}
'computer' {
$computer = $adObject | Get-ADComputer -Properties Description
# you want to output only the computers where the Description property holds the computer name
if ($computer.Description -like '*$($computer.Name)*') {
$computer | Select-Object Name, Description, #{Name = 'Type'; Expression = {'Computer'}}
}
}
# perhaps you don't want subgroups in your report, in that case just remove or comment out the next part
'group' {
$adObject | Get-ADGroup -Properties Description | Select-Object Name, Description, #{Name = 'Type'; Expression = {'Group'}}
}
}
}
# show the result on screen
$result | Format-Table -AutoSize
# save the result as Csv file
$outFile = Join-Path -Path 'X:\Somewhere' -ChildPath ('{0}_members.csv' -f $groupName)
$result | Export-Csv -Path $outFile -NoTypeInformation -UseCulture
The -UseCulture switch makes sure the Csv file uses the delimiter character your local Excel expects. Without that, a comma is used
Interesting reads:
about_Operators
Adam the Automator
Learn Powershell | Achieve More
and of course StackOverflow
Good Morning Guys,
I write this script to export multiple users in multiple groups in a CSV file.
In addition to not exporting anything, I cannot insert a column in the CSV where the user's appatenency group is specified. Just the one with the name "vpn-*", like vpn-users
Powershell Version 4.0
$Data = $UserData = #()
$GroupName = Get-ADGroup -Filter {name -like "VPN-*"} -Properties Name | Select-Object Name
Foreach ($group in $GroupName)
{
$UserData = Get-ADGroupMember -Identity {$group}
Where objectClass -eq 'user' |
Get-ADUser -Properties Name, UserPrincipalName, description, Enabled |
Select-Object Name, UserPrincipalName, description, Enabled
}
$UserData | export-csv "c:\members2.csv"
I see a number of issues with the posted code. Some are mere preferences, but others look like they would affect the outcome.
-Properties Name isn't needed in the initial Get-ADGroup command. The Name property is returned by default.
Respectful to #Theo's comment re: -ExpandProperty, however, I prefer not to use that unnecessarily. You don't even need the first Select-Object command, just reference the property and it will unroll and return a string array. Property unrolling is supported as of PowerShell Version 3.
Your argument to the -Filter parameter should be a string. I myself have a hard time breaking the habit of wrapping those queries in script blocks {...}, however, there are some specifics of the AD cmdlets, and using a string is a best practice. Basically, the argument takes a string type, if you give it a script block it will convert it to a string and that process may not always work as desired.
It's better to store your AD properties in an array you can cite multiple times. Normally you would've only needed to add 'Description' but considering you were also using it in a later Select-Object command it makes more sense to add all the desired properties to an array.
Personally, I prefer not to use simplified syntax. I don't know what the community's opinion is on that but I rewrote using my preference.
You were also missing |' before the Where-Object command.
And, yes you would have to move the Export-Csv inside the loop to output data per loop iteration. Using the -Append parameter to avoid overwriting it on every iteration.
Untested Example:
$ADProps = 'Name', 'UserPrincipalName', 'description', 'Enabled'
$GroupName = (Get-ADGroup -Filter "name -like 'VPN-*'" ).Name
Foreach ( $Group in $GroupName )
{
$UserData =
Get-ADGroupMember -Identity $Group |
Where-Object{ $_.objectclass -eq 'user' } |
Get-ADUser -Properties $ADProps |
Select-Object ($ADProps += #{Name = 'Group'; Expression = { $Group }})
$UserData | export-csv "c:\members2.csv" -NoTypeInformation -Append
}
I am trying to send a user name (SamAccountName) down the PowerShell Pipeline to find a computer based on the Description property in Active Directory:
The Description property is always "something-UserName"
I know I don't need to send the variable down the pipeline and can simply express it in the filter but I have s specific use case where I need to do this.
This is what I have tried:
"bloggsJ" | %{Get-ADComputer -server domain.com -Filter * -Properties Description | ?{$_.Description -eq "something-$_"}} | select Name
This produces nothing even though there is a computer with a description property of "Something-bloggsJ" on that domain.
Any advice please.
Instead of using the -eq operator, I would use -like.
Something like this:
"bloggsJ", "IanB" | ForEach-Object {
$name = $_
Get-ADComputer -Filter * -Properties Description |
Where-Object {$_.Description -like "*-$name"}
} | Select-Object Name
Inside the ForEach-Object loop, the $_ automatic variable is one of the usernames. Inside the Where-Object clause, this $_ variable represents one ADComputer object, so in order to have the username to create the -like string, you need to capture that name before entering the Where-Object clause.
I believe you are missing the underscore for $_ variable:
"ivan" | ForEach-Object -Process { Get-ADComputer -Filter * -properties description | Where-Object -Property description -eq "something-$_"}
this one is working ...
This question already has answers here:
How to get an object's property's value by property name?
(6 answers)
Closed 5 years ago.
I am working on a script which takes Hostnames from a CSV, Files them against Get-ADComputer and then saves certain Objects in certain columns of the original CSV.
While the solution seems like a basic Task (code below), my problem is, that the Output of Get-ADComputer always (you can see I played around with Out-String but also tried other formatting options) contains a lot of NewLine characters or other formatting issues which make the CSV confusing.
Clear-Host
Import-Module ActiveDirectory
$import = Import-Csv 'XXX' -Delimiter ';'
Foreach ($row in $import){
$hostname = $row.HOSTNAME
if($hostname.length -gt 3){
$computer = Get-ADComputer -Filter {Name -like $hostname} -Properties LastLogonDate, LastLogonTimeStamp
$row.AD_LastLogon.ToString() = $computer | Select-Object LastLogonDate | Select-Object -first 1 | FT -HideTableHeaders | Out-String
$row.AD_LLTimestamp = $computer | Select LastLogonTimestamp |Select-Object -first 1 | FT -HideTableHeaders | Out-String
}
}
$import | Export-Csv 'XXX' -Delimiter ';' -NoType
My question now is, if anyone could help with a method to get the bare string result of for example Get-ADComputer's LastLogonDate, without any formatting or headers included.
Thanks in advance!
Use the -ExpandProperty parameter of Select-Object to extract just the parameter you want. You can only specify one parameter to exapand at a time.
$row.AD_LastLogon = $computer | Select-Object -ExpandProperty LastLogonDate -First 1 | Out-String
$row.AD_LLTimestamp = $computer | Select-Object -ExpandProperty LastLogonTimestamp -First 1
I don't believe the -First 1 should be necessary. Get-ADComputer shouldn't be finding multiple computers with the same name.
Also, you shouldn't need to retrieve both LastLogonDate and LastLogonTimestamp. The former is the same value as the latter, just converted to a DateTime from the irritating NT Time Epoch that LastLogonTimestamp uses. Have you got a system that requires both?
Finally, just a note but this:
$row.AD_LastLogon.ToString() = $computer | [...]
It doesn't make sense. You can't assign a value to a method. I would be surprised if that didn't error or otherwise do nothing at all.
I wish to list the index of an item in a result table.
In this case I am using get-aduser with the filter option.
I am then using format-table with -Property to display only the properties I want.
I previously used a loop to display the items along with a counter to emulate the index but this was messy and I wanted it in a table.
Code:
$search_param = read-host "Enter search string: "
$search_param = "*" + $search_param + "*" # Construct search param.
$search_result = Get-ADUser -Filter {Surname -like $search_param -or GivenName -like $search_param -or SamAccountName -like $search_param}
$search_result | format-table -Property GivenName,Surname,SamAccountName
How can I get format-table to display the item index/position without using some kind of loop? ie, is there some kind of 'hidden' index property that I can simply provide to format-table?
The format-table CmdLet -Property param can be a new calculated property see Format-table help.
Here is an example with a computed index on Get-Process objects.
$index=0
Get-Process | Format-Table -Property #{name="index";expression={$global:index;$global:index+=1}},name,handles
The ForEach-Object cmdlet can be used to create a calculated "index" property for the Format-Table cmdlet
For Example:
$search_result | ForEach-Object {$index=0} {$_; $index++} | Format-Table -Property #{ Label="index";Expression={$index}; Width=5 },GivenName,Surname,SamAccountName
Additional References:
Adding Array Index Numbers to PowerShell Custom Objects
ForEach-Object
Format-Table
In my opinion you can't, you need to extend the objects with an Index property and include it in your Format-Table command.
$procs = Get-Process
#option 1
$procs | Select #{N='Index'; E={$procs.IndexOf($_)}}, name, handles
#option 2
$procs | Format-Table -Property #{name="index";expression={$procs.IndexOf($_)}},name,handles