Allocating values to specific csv columns in Powershell - powershell

I'd like to ask if anybody can please advise a way how to allocate a value in variable to a column in csv.
For example:
TriggeredBy | TriggeredTime | Firstname | Lastname | Username | ....
Throughout my script I'm modifying input data and on the go I'd like it to fill in the row to the relevant column.
Then another script from a different server has to take over, read the calculated values and add its calculated results into its dedicated columns.
The output would be a row where I can see that all the results.
In the end it's supposed to serve as a sort of database.
Sample of script here would be:
$aduser = Get-ADUser -Filter {sAMAccountName -like $username} -Properties *
$Firstname = $aduser.GivenName
$Firstname | Export-CSV -Path $filepath | Select-Object "First Name"
$Lastname = $aduser.Surname
$Lastname | Export-CSV -Path $filepath | Select-Object "Last Name"
$TriggeredBy = $env:UserName
$TriggeredBy | Export-CSV - Path $filepath | Select-Object "TriggeredBy"
...
Throughout the process all saved in one relevant row. Next process does the same for the following row etc...
The "Export-CSV ...." part is obviously wrong, I would need some alternative
Many thanks!

Use Select-Object with calculated properties:
Get-ADUser -Properties * -Filter "sAMAccountName -eq `"$username`"" | #`
Select-Object #{ n='FirstName'; e='GivenName' },
#{ n='Last Name'; e='Surname' },
#{ n='TriggeredBy'; e={ $env:UserName } } |
Export-Csv -NoTypeInformation -Literalpath $filePath
Note that I've used a string as the -Filter argument, because that's what it ultimately becomes anyway. Using script-block literal syntax { ... } is tempting, but ultimately causes more problems than it solves - see this answer.
Note that in Windows PowerShell Export-Csv creates ASCII(!)-encoded files by default, which can result in loss of information; use the -Encoding parameter to change that.
PowerShell [Core] v6+, by contrast, commendably defaults to (BOM-less) UTF-8; also, the
-NoTypeInformation switch is no longer necessary there.
If you want to append to an existing CSV file (which needs to have the same column structure), use the -Append switch.

Related

Powershell AD: filter description -like $variable => contains $variable

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

How to pipe results of a foreach loop to an output file?

I have the following code that gets usernames from a list and then retrieves their emails.
I'd like to have this outputted to eventually send automatic emails to these specific addresses.
With the code below, only the last object in the text file is recorded in the outfile.
$users = (get-content c:\temp\Fredro.txt)
foreach ($EUT in $users) {
Get-ADUser -Identity $EUT | Select-Object UserPrincipalName | Out-File -filepath C:\temp\exomailinglist.txt}
How to pipe results of a foreach loop to an output file?
You are overwriting the file on every pass through your foreach loop if an ADUser is found. As Abraham Zinala mentioned in comments if you were to add -Append to the Out-File cmdlet this would solve your problem of the file only containing the last item. I would also recommend adding -ExpandProperty to Select-Object to avoid having the header "UserPrincipalName" also added to the file each time.
$users = (Get-Content c:\temp\Fredro.txt)
foreach ($EUT in $users) {
Get-ADUser -Identity $EUT |
Select-Object -ExpandProperty UserPrincipalName |
Out-File -FilePath C:\temp\exomailinglist.txt -Append
}
Rather than writing to the file in the foreach loop for each user though I would instead recommend to capture all ADUsers first and then write all of the items at once to the file, possibly like this:
$users = (Get-Content c:\temp\Fredro.txt)
$adUsers = foreach ($EUT in $users) {
Get-ADUser -Identity $EUT |
Select-Object -ExpandProperty UserPrincipalName
}
$adUsers | Out-File -FilePath C:\temp\exomailinglist.txt
And lastly, the best option in my opinion, combine it all into one pipeline which would look like this.
Get-Content c:\temp\Fredro.txt |
Get-ADUser |
Select-Object -ExpandProperty UserPrincipalName |
Out-File -FilePath C:\temp\exomailinglist.txt
This method would avoid the foreach loop completely. Get-ADUser accepts Identity from the pipeline byvalue so we can just pipe each line from Get-Content directly. Out-File will wait on all items from the pipeline before writing to the file.

Filter enabled AD users from CSV file

I have a script to import a list of users and want to check if any of these users are disabled. I did try to run the script below but it doesn't filter the users in the CSV file it filters everyone in the entire organization. any suggestions would be appreciated. displayname and SIP address in one of the headers in the CSV file if needed to use the header.
Import-CSV -Path .\Piscataway-+1732.csv | ForEach-Object {
Get-ADUser -Filter "Enabled -eq '$true'" | select Enabled,EmailAddress,SamAccountName
} | Export-CSV .\results77.csv -NoTypeInformation
You have several issues:
You are piping From Import-Csv to ForEach-Object. So Get-ADUser doesn't really know you are piping it input objects.
Get-ADUser's -Identity parameter is by value, not by property name. so you need to echo the appropriate column to send it down the pipe.
If you pipe and use the -Filter parameter the filter is going to apply to the whole domain. It's not going to limit the filter to what you piped in.
If you want the email address to be output you have to tell Get-ADUser to retrieve it.
Try something like this:
Import-CSV -Path .\Piscataway-+1732.csv |
ForEach-Object{ $_.samAccountName }
Get-ADUser -Properties mail |
Where-Object{ $_.Enabled }
Select-Object Enabled,mail,SamAccountName |
Export-CSV .\results77.csv -NoTypeInformation
Note: The Property for the email address is "mail".
Note: Since we don't have a sample of the CSV file the above example
assumes there's a column names samAccountName.
Now, if you want the output to come from the CSV file but validate it according to the user's status in AD we have to change the approach. As always there are several ways to do this.
Example 1:
Import-CSV -Path "c:\temp\test.csv" |
Select-Object #{Label = 'Enabled'; Expression = { ( Get-ADUser $_.samAccountName ).Enabled } },EmailAddress,samAccountName |
Export-CSV -Path "c:\temp\Output.csv" -NoTypeInformation
This again assumes the column name (samAccountName). It also assumes there is not already an "enabled" column. So we are adding a property called enabled that we're getting via Get-ADUser. Then finally re-exporting to Csv.
Example 2:
$CsvData = Import-CSV -Path "c:\temp\test.csv"
$EnabledUsers =
(
$CsvData |
ForEach-Object{ $_.samAccountName } |
Get-ADUser |
Where-Object{ $_.Enabled }
).samAccountName
$CsvData |
Where-Object{ $EnabledUsers -contains $_.samAccountName } |
Select-Object #{Label = 'Enabled'; Expression = { $true } },EmailAddress,samAccountName |
Export-Csv -Path "c:\temp\Output.csv" -NoTypeInformation
Example 1 is great for small jobs but too many individual calls to Get-ADUser might be slow for larger runs. In this example Import the CSV data once. Then use it to get a flat list of those entries that are enabled in AD. Once you have that you can use the -contains operator to check if the account is enabled. Once again there's a little extra work to add the "Enabled" property.
This should give you a general idea. There are probably a dozen more ways to do this, but hopefully this give you a good idea of what has to happen. Let me know if this helps.

How do I get Powershell to output Get-ADUser -Filter * as comma delimited?

I have a simple Powershell script that I want to use to grab all the users in AD and show specific properties. Here is the heart of my script:
$id = "*"
Get-ADUser -Filter {SAMAccountName -like $id} -Properties * | Select-Object -Property SAMAccountName,Name,PasswordNeverExpires,LockedOut,PasswordLastSet,LastLogOnDate,CanonicalName
The full script has an input parameter to set $id so that it can be a single ID, a list of IDs (such as "bsmith, jdoe, gmanning"), or * to get all accounts.
Here's my problem: When using, *, I need this to output as comma delimited.
Here's the catch: The output cannot be to a CSV file--or any other type of file.
The reason being is that I'm writing this script to be used on N-Enable's N-Central monitoring suite of software. You don't need to know N-Central to help with my problem, just understand that N-Central uses its own software to run Powershell scripts on clients and returns the results into a txt file that cannot be changed to a csv file (or formatted in any other way than what it has hard-coded).
What this means is that my results have to either be what would show up on the screen or in a variable (such as $results=Get-ADUser -Filter * ....). I cannot output to any type of file, which leaves out Export-CSV as an option.
I've tried other types of formatting to no avail (such as with -f). The issue seems to be with the way Powershell grabs all AD Users using the * wildcard. It seems to grab them all as one big object, so I am unable to get my output to have a comma between all the properties so that I get a comma-delimited output. Thus, when I get the results back from N-Central as a .txt file, all the data is there, but there are no commas in between the properties for me to then open the .txt file as comma-delimited in Excel (or tab-delimited for that matter).
Does anyone have a solution that will allow me to format Get-ADUser -filter * so that it is comma-delimited without using export to file?
UPDATE: Ok, I thought I was keeping things easy by not posting my full script but it seems I've done the opposite. So, below is my full script. Anyone should be able to run this to see the results:
function Get-ADUserInfo
{
[CmdletBinding()]
param(
#[Parameter(Mandatory=$True)]
[string[]]$Users= '*'
)
Begin {
$maxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.Days
$Headers="ID, Name, Password Never Expires?, Locked Out, Password Last Set, Expiry Date, Last Logon Date, OU Path"
}
Process {
foreach ($id in $Users)
{
$results=Get-ADUser -Filter {SAMAccountName -like $id} -Properties * | select -property SAMAccountName,Name, PasswordNeverExpires,LockedOut,PasswordLastSet,(#{Expression={$_.PasswordLastSet.AddDays($maxPasswordAge)}}), LastLogOnDate,CanonicalName | `
ConvertTo-CSV -NoTypeInformation
}
}
End {
$Headers
$results
}
}
Get-ADUserInfo -Users
Some notes:
When calling Get-AdUserInfo -Users, the script needs to work by entering a single ID, *, or multiple IDs separated by a comma when using the -Users parameter.
Using ConvertTo-CSV solved my biggest problem, comma separated output,thanks all.
I'd like to get rid of the headers that are auto-created as well ("SAMAccountName","Name","PasswordNeverExpires","LockedOut","PasswordLastSet","$_.PasswordLastSet.AddDays($maxPasswordAge)","LastLogOnDate","CanonicalName"). How can I do that? I've tried -skip 1 but that doesn't work with * and removes everything (including the data) if used with a single ID or IDs separated with commas. I can't get -ExpandProperty to work either. Adding format-table -hidetableheaders at the end doesn't do anything as well
So you could use something like this then
$props = "SAMAccountName","Name","PasswordNeverExpires","LockedOut","PasswordLastSet","LastLogOnDate","CanonicalName"
$results = Get-ADUser -Filter * -Properties $props | Select $props | ConvertTo-Csv -NoTypeInformation
This uses the $props array to make the actual query readable and enforce property order. Most of those properties are returned by default, like samaccountname, so it is not required to specify them but no harm done.
$results would contain a quoted comma delimited output. If the quotes bother you they should be removed with a simple -replace
$results = $results -replace '"'
Aside
As others have mentioned you are wasting time using -Properties * you should only return the properties that you need. Which is, again, why I used $props.
Update from comments
If you want to remove the header column you just need to -Skip that from the output. At the end of the code that populates results just add Select-Object
$results = Get-ADUser -Filter * -Properties $props | Select $props | ConvertTo-Csv -NoTypeInformation | Select-Object -Skip 1
Also to cover your calculated property the easiest way that I have found so far is to add another Select-Object. Not the way I would want to but for now it works.
$results = Get-ADUser -Filter * -Properties $props |
Select $props | Select-Object *,#{L="pWD";Expression={$_.PasswordLastSet.AddDays($masPasswordAge)}} |
ConvertTo-Csv -NoTypeInformation | Select-Object -Skip 1
Game Changer
So you made some pretty big changes to your example by including your function. Try this on for size now.
function Get-ADUserInfo
{
[CmdletBinding()]
param(
#[Parameter(Mandatory=$True)]
[string[]]$Users= '*'
)
Begin{
$results = #()
$maxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.Days
$Headers= #{Label="ID";Expression={$_.SAMAccountName}},
#{Label="Name";Expression={$_.Name}},
#{Label="Password Never Expires?";Expression={$_.PasswordNeverExpires}},
#{Label="Locked Out";Expression={$_.LockedOut}},
#{Label="Password Last Set";Expression={$_.PasswordLastSet}},
#{Label="Expiry Date";Expression={$_.PasswordLastSet.AddDays($maxPasswordAge)}},
#{Label="Last Logon Date";Expression={$_.LastLogOnDate}},
#{Label="OU Path";Expression={$_.CanonicalName}}
}
Process{
foreach ($id in $Users){
$results += Get-ADUser -Filter {SAMAccountName -like $id} -Properties PasswordNeverExpires,LockedOut,PasswordLastSet,LastLogOnDate,CanonicalName | select $Headers
}
}
End{
$results | ConvertTo-CSV -NoTypeInformation
}
}
Get-ADUserInfo -Users
$Headers= contains a collection of calculate properties most of which are there the change the header. It does not need to be done this was and you could have just manually added a header line before the output of contents. This solution however is more in line with what PowerShell is capable of.
We collect all of the users in the array $results and in the End block convert that to CSV output which would not contain your custom headers.
$id = "*"
$userlist = Get-ADUser -Filter {SAMAccountName -like $id} -Properties SAMAccountName,Name,PasswordNeverExpires,LockedOut,PasswordLastSet,LastLogOnDate,CanonicalName | ConvertTo-CSV -NoTypeInformation
$userlist will be an array of users stored in CSV formatted lines
Edit: Combined -Properties * | Select [propertylist] and get rid of the pull of all properties.
Edit: included -NoTypeInformation so that the output is pure CSV.
Note: Something should be done about the filter.

Output data with no column headings using PowerShell

I want to be able to output data from PowerShell without any column headings. I know I can hide the column heading using Format-Table -HideTableHeaders, but that leaves a blank line at the top.
Here is my example:
get-qadgroupmember 'Domain Admins' | Select Name | ft -hide | out-file Admins.txt
How do I eliminate the column heading and the blank line?
I could add another line and do this:
Get-Content Admins.txt | Where {$_ -ne ""} | out-file Admins1.txt
But can I do this on one line?
In your case, when you just select a single property, the easiest way is probably to bypass any formatting altogether:
get-qadgroupmember 'Domain Admins' | foreach { $_.Name }
This will get you a simple string[] without column headings or empty lines. The Format-* cmdlets are mainly for human consumption and thus their output is not designed to be easily machine-readable or -parseable.
For multiple properties I'd probably go with the -f format operator. Something along the lines of
alias | %{ "{0,-10}{1,-10}{2,-60}" -f $_.COmmandType,$_.Name,$_.Definition }
which isn't pretty but gives you easy and complete control over the output formatting. And no empty lines :-)
A better answer is to leave your script as it was. When doing the Select name, follow it by -ExpandProperty Name like so:
Get-ADGroupMember 'Domain Admins' | Select Name -ExpandProperty Name | out-file Admins.txt
If you use "format-table" you can use -hidetableheaders
add the parameter -expandproperty after the select-object, it will return only data without header.
The -expandproperty does not work with more than 1 object. You can use this one :
Select-Object Name | ForEach-Object {$_.Name}
If there is more than one value then :
Select-Object Name, Country | ForEach-Object {$_.Name + " " + $Country}
Joey mentioned that Format-* is for human consumption. If you're writing to a file for machine consumption, maybe you want to use Export-*? Some good ones are
Export-Csv - Comma separated value. Great for when you know what the columns are going to be
Export-Clixml - You can export whole objects and collections. This is great for serialization.
If you want to read back in, you can use Import-Csv and Import-Clixml. I find that I like this better than inventing my own data formats (also it's pretty easy to whip up an Import-Ini if that's your preference).
First we grab the command output, then wrap it and select one of its properties. There is only one and its "Name" which is what we want. So we select the groups property with ".name" then output it.
to text file
(Get-ADGroupMember 'Domain Admins' |Select name).name | out-file Admins1.txt
to csv
(Get-ADGroupMember 'Domain Admins' |Select name).name | export-csv -notypeinformation "Admins1.csv"
$server = ('*')+(Read-Host -prompt "What Server Context?")+'*'
$Report = (Get-adcomputer -SearchBase "OU=serverou,DC=domain,DC=com" -filter {name -like $server} -SearchScope Subtree|select Name |Sort -Unique Name)
$report.Name | Out-File .\output\out.txt -Encoding ascii -Force
$Report
start notepad .\output\out.txt
Put your server SearchBase in above.
If you are not sure what your server OU is try this function below...
#Function Get-OSCComputerOU($Computername)
{
$Filter = "(&(objectCategory=Computer)(Name=$ComputerName))"
$DirectorySearcher = New-Object System.DirectoryServices.DirectorySearcher
$DirectorySearcher.Filter = $Filter
$SearcherPath = $DirectorySearcher.FindOne()
$DistinguishedName = $SearcherPath.GetDirectoryEntry().DistinguishedName
$OUName = ($DistinguishedName.Split(","))[1]
$OUMainName = $OUName.SubString($OUName.IndexOf("=")+1)
# $Obj = New-Object -TypeName PSObject -Property #{"ComputerName" = $ComputerName
# "BelongsToOU" = $OUMainName
# "Full" = $DistinguishedName}
$Obj = New-Object -TypeName PSObject -Property #{"Full" = $DistinguishedName}
$Obj
}
Makes sure to run the Get-OSCComputerOU Servername with a select -expandproperty Full filter.
Then just plug in the response to the Searchbase...
All thanks to http://www.jaapbrasser.com