adding variable to format list output - powershell

I have a question about adding a variable to the output of format-list. When I run the command:
get-CsAdUser | Format-List DisplayName, Enabled
I get the output
DisplayName : user01
Enabled : True
DisplayName : user02
Enabled : False
I have a variable $var1 = "folder one" that I need to add to the output so it looks like :
DisplayName : user01
Enabled : True
folder one
DisplayName : user02
Enabled : False
folder one
Anyone have an idea on how to do this? Thanks

On a meta note:
PetSerAl, as he often does, has provided an effective answer in a comment.
However, it is preferable to have an actual answer post that can be marked as accepted so as to signal to future readers what solution truly solved the OP's problem.
As PetSerAl notes:
get-CsAdUser | Format-List DisplayName, Enabled, #{Label = 'Folder'; Expression = {$var1}}
adds a third property to each input object's output that prints the value of variable $var1 as an ad-hoc, calculated property named Folder, following the preexisting DisplayName and Enabled properties.
The #{ Label = ...; Expression = ... } part of the command is a PowerShell hashtable literal that is an instance of a calculated property, which you can use with Select-Object, Format-Table, and Format-List, as described in this answer of mine.

Related

Unsure if Sort-Object works like I think it works

I have a Variable called $CompleteDataSetOldDb with 26805 PSCustomObject in it. The Objects all look like this (all have the same PropertyNames):
Klasse : TbAEinschubelementHalter
NeueKlasse : EinschubelementHalter
ArtikelNr : 12.Z36D0080.12
NameDE : Halteteil Höhe D, weiss Set für Einschubelemente
NameFR : adaptateur hauteur D, blanc Set pour inserts
Parameter : FarbeZarge
ParameterValue : Stahl Weiss
ItemGroupID : 12
Now I know that I also have duplicates in this Variable. I'd like to get rid of them. With duplicates I mean that they have the exaxt same ArtikelNr, Parameter and ParameterValue combination. The combination of these 3 properties can only be in my Variable once.
Here you can see one entry that is exactly the same:
Klasse : TbXOrgalineQuerteilerAufnahme
NeueKlasse : OrgalineQuerteilerAufnahme
ArtikelNr : 12.Z40C0002Z.12
NameDE : Querteileraufnahme C weiss zu Profil Z40L1077
NameFR : Support séparateur, blanc pour Profil Z40L1077
Parameter : FarbeZarge
ParameterValue : Stahl weiss
ItemGroupID : 31
Klasse : TbXOrgalineQuerteilerAufnahme
NeueKlasse : OrgalineQuerteilerAufnahme
ArtikelNr : 12.Z40C0002Z.12
NameDE : Querteileraufnahme C weiss zu Profil Z40L1077
NameFR : Support séparateur, blanc pour Profil Z40L1077
Parameter : FarbeZarge
ParameterValue : Stahl weiss
ItemGroupID : 31
They both have ArtikelNr 12.Z40C0002Z.12, Parameter FarbeZarge and ParameterValue Stahl weiss so I only need it in my Variable once.
I tried to filter them simply like this:
$CompleteDataSetOldDB | Sort-Object ArtikelNr, Parameter, ParameterValue -Unique
And from my 26805 objects, only 15067 still remain.
Did my Sort-Object work like I intended, namely filtered out all duplicates of objects that have the same combination of the 3 propertys? Is there a Command I can run to check this?
Yes, it works like you think. It's easy enough to test using a contrived subset of your data, isn't it?
In reality, if you have a reason not to trust Sort-Object, then you should verify it manually. If you don't trust Sort-Object, I don't understand why you would trust another Powershell command at all. They may use the same logic or miss the same corner cases (like leading or trailing whitespace, not slugging non-breaking spaces, etc.).
If I were going to verify it manually, I would start with Group-Object.
$CompleteDataSetOldDB | Sort-Object -Property ArtikelNr, Parameter, ParameterValue |
Group-Object -Property ArtikelNr, Parameter, ParameterValue -NoElement
That should return each unique group and the number of elements in each group. You may want to pipe the output to Format-Table -Autosize or Export-Csv to see everything.
Alternately, you could do this:
$CompleteDataSetOldDB | Sort-Object -Property ArtikelNr, Parameter, ParameterValue -Unique |
Export-Csv Unique.csv -NoTypeInformation
$CompleteDataSetOldDB | Sort-Object -Property ArtikelNr, Parameter, ParameterValue |
Export-Csv Duplicated.csv -NoTypeInformation
Then open Duplicated.csv with a text editor that has a function which can eliminate duplicate rows. Eliminate the duplicate rows, then compare the de-duplicated Duplicated.csv with Unique.csv using WinMerge or similar.
If I was still not convinced, then I would import my entire data set into an SQL RDBMS and then execute:
SELECT DISTINCT ArtikelNr, Parameter, ParameterValue
FROM StagingTable
Note that I don't recommend using Excel for this because it silently alters data.
This answer complements Bacon Bits' helpful answer, which solves your problem.
There is a caveat with respect to Sort-Object -Unique in combination with -Property (property-based sort criteria):
-Unique only applies to the sort criteria values, and not to the objects as a whole.
That is, if the properties not being sorted by differ among objects that share the same sort-criteria property values, you will lose information, as only one among those objects will be output, and which one isn't predictable.
(This doesn't seem to apply in your case, but it's worth pointing out in general.)
For example:
PS> [pscustomobject] #{ one=1; other='A' }, [pscustomobject] #{ one=1; other='B' } |
Sort-Object one -Unique
one other
--- -----
10 A # !! Only 1 object is output among all where .one equals 1
To prevent that, Group-Object must be used, which has the same syntax for sort criteria and allows examining all objects that share sort-criteria (grouping-criteria) values via the output objects' .Group property.
On a somewhat related note:
For the purposes of uniqueness detection (and also sorting, though it doesn't make sense to sort [pscustomobject] instances as a whole), PowerShell considers all [pscustomobject] instances to be the same even if they have completely unrelated properties (and/or values):
For example:
# Note the different property names (and values).
PS> [pscustomobject] #{foo='A'}, [pscustomobject] #{bar='B'}, [pscustomobject] #{baz='C'} |
Select-Object -Unique
foo
---
A # !! Only the *first* object is output, because all are considered the same.

Powershell export nested object arrays into CSV

When i look into my object arra and type a $obj[2] (as exam) I'm getting
Name : audit_event
UUID : c6479a6f-f1bd-4759-9881-fcb493821aff
Timestamp : 17-06-20 13:30:48 +00:00
Fields : {[audit_schema_version, 1], [event_time, 17-06-20 13:30:48 +00:00], [sequence_number, 1], [action_id, 541934402]...}
Actions : {}
I would like to get all fields into a single csv file.
So first I started to find at least the fields, but dispite some solutions I saw i'm not getting it OK.
foreach ($UUID in $logsOBJECT[2].UUID) {
echo $UUID
foreach ($field in $logsOBJECT.$UUID.Keys) {
echo $field
}
}
This doesn't work.
I'm not a Powershell developer so quite novice.
I have to use Powershell because Synaps Analytics doesn't give a better option to read and process its logfiles.
Kind regards, Harry
Given an object that looks like this in JSON:
[{
"Name": "audit_event",
"UUID": "c6479a6f-f1bd-4759-9881-fcb493821aff",
"Timestamp": "17-06-20 13:30:48 +00:00",
"Fields": [["audit_schema_version", 1], ["event_time", "17-06-20 13:30:48 +00:00"], ["sequence_number", 1], ["action_id", 541934402]],
"Actions": {}
}]
(You can generate that by using $obj | ConvertTo-Json so it's easier for others to reproduce)
First we loop through the $obj list by passing it to ForEach-Object, or % for short. For each element we create a $result object that contains all the data, except the Fields property.
Then we loop through the fields property on the object. Each field is itself a list, where the first (0) element is the name, and the second (1) is the value. For each field, we add a property to the $result object with the name and value of the field.
When this is done we return the $result object to the pipeline, and that gets passed to Export-Csv which writes it to a file.
$obj | % {
$result = $_ | Select-Object * -ExcludeProperty Fields
$_.Fields | % {
$result | Add-Member -Name $_[0] -Value $_[1] -MemberType NoteProperty
}
return $result
} | Export-Csv -Path C:\test.csv -Encoding UTF8 -NoTypeInformation
I don't have your exact PS module of SynapsAnalystics...
But it seems to be a problem accessing nested arrays in Powershell.
Here I have an example with Windows services:
PS C:\WINDOWS\system32> $servic[20] | fl
Name : BrokerInfrastructure
DisplayName : Background Tasks Infrastructure Service
Status : Running
DependentServices : {workfolderssvc, WMPNetworkSvc, WSearch, embeddedmode}
ServicesDependedOn : {DcomLaunch, RpcSs, RpcEptMapper}
CanPauseAndContinue : False
CanShutdown : False
CanStop : False
ServiceType : Win32ShareProcess
Here, if I want the output of $servic.DependentServices I need to know the Keys\Propertys of $servic.DependentServices. ie,
You can get that by :
PS C:\WINDOWS\system32> $servic[20].DependentServices
Status Name DisplayName
------ ---- -----------
Stopped workfolderssvc Work Folders
Running WMPNetworkSvc Windows Media Player Network Sharin...
Running WSearch Windows Search
Stopped embeddedmode Embedded Mode
So the Propertys here are
Status Name DisplayName etc...
$servic[20].DependentServices would be similar to $obj[2].Fields in your case.
Try and see the Keys or Property's within $obj[2].Fields then decide which Property you want to loop through.
you can get that with
$obj[2].Fields | get-Module (this will give all parameters)
Then you can loop through the required Properties, like in my case:
foreach ($echserv in $servic[0-2])
{
write-host "*****************Service******************"
echo $echserv.Name
Write-Host "####DependentServices####"
foreach ($echDependServic in $servic.DependentServices.DisplayName)
{
echo $echDependServic
}
}
which would give output:
*****************Service******************
XboxGipSvc
####DependentServices####
Smartlocker Filter Driver
Agent Activation Runtime_ea2d3
Agent Activation Runtime
Windows Audio
Agent Activation Runtime_ea2d3
Agent Activation Runtime
Xbox Live Networking Service
.
.
.
Hope this helps with your problem.
PS: There are better ways to display your output using hashtables in Powershell. This can later be used to export to CSV etc..

Removing samaccountname from group after N time - powershell

I am looking to find a way to remove a user from a group after a specific amount of time.
Via the below link I found that you can find users that were added with 10 days or more:
https://gallery.technet.microsoft.com/scriptcenter/Find-the-time-a-user-was-a0bfc0cf#content
As an output I get the example below:
ModifiedCount : 2
DomainController : DC3
LastModified : 5/4/2013 6:48:06 PM
Username : joesmith
State : ABSENT
Group : CN=Domain Admins,CN=Users,DC=Domain,DC=Com
I would like to return SamAccountName instead of Username.
I was trying to look at code and I know this is something to do with the variable $pattern But I am not that good in powershell to know at first sight.
Looking at that code, the Username property IS the SamAccountName.
However, if you want to change that label, you can either simply change it on line 106 from
Username = [regex]::Matches($rep.context.postcontext,"CN=(?<Username>.*?),.*") | ForEach {$_.Groups['Username'].Value}
into:
SamAccountName = [regex]::Matches($rep.context.postcontext,"CN=(?<Username>.*?),.*") | ForEach {$_.Groups['Username'].Value}
Or change the label in the objects returned afterwards with a calculated property:
$returnedObjects | Select-Object #{Name = 'SamAccountName'; Expression = {$_.Username}}, * -ExcludeProperty Username

PowerShell: ConvertFrom-Json to export multiple objects to csv

As you probably understand from the title, I'm new to PowerShell, having a hard time even trying to describe my question. So please forgive my terminology.
Scenario
I am using PowerShell to query the audit log of Office 365. The cmdlet Search-UnifiedAuditLog returns "multiple sets of objects"(?), one of which has an array of other objects(?). The output is JSON if I got this right.
Here is an example of what is returned (I will call it one "Set of Objects"):
RunspaceId : xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
RecordType : AzureActiveDirectoryStsLogon
CreationDate : 21/02/2017 12:05:23
UserIds : xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Operations : UserLoggedIn
AuditData : {"CreationTime":"2017-02-21T12:05:23","Id":"{"ID":"00000000000000000","Type":3}],"ActorContextId":"xxxxxxxxxxxxxxxxxxxxxxxxx","ActorIpAddress":"xxxxxxxxxxxxx","InterSystemsId":"xxxxxxxxxxxxxxxxx","IntraSystemId":"000000000000-000000-000","Target":[{"ID":"00-0000-0000-c000-000000000000","Type":0}],"TargetContextId":"xxxxxxxxxxxxxxxxxx","ApplicationId":"xxxxxxxxxxxxxxxxxxxxxxxxxx"}
ResultIndex : 1
ResultCount : 16
Identity : xxxxxxxxxxxxxxxxxxxxxxxxxxx
IsValid : True
ObjectState : Unchanged
Now, I want some of the content of the AuditData line exported to a csv (normally containing much more data than copied here). This works fine for one "set of objects" (like the one above). To do this I use:
$LogOutput = Search-UnifiedAuditLog -StartDate 2/20/2017 -EndDate 2/23/2017 -ResultSize 1
$ConvertedOutput = ConvertFrom-Json -InputObject $LogOutput.AuditData
$ConvertedOutput | Select-Object CreationTime,UserId,ClientIP | Export-Csv -Path "C:\users\some.user\desktop\users.csv
ResultSize returns 1 instead of multiple "sets of objects". The ConvertFrom-Json does not work if I remove ResultSize.
So the question is:
Can I loop through all the "set of objects" and convert from json and have this exported line-by-line on a csv? Resulting in something like this:
UserId,Activity,UserIP
this#user.com, loggedIn, 10.10.10.10
that#user.org, accessedFile, 11.11.11.11
A pedagogic answer would be very, very much appreciated. Many thanks!
Instead of -ResultSize, try using Search-UnifiedAuditLog <args> | Select-Object -ExpandProperty AuditData | ConvertFrom-Json
This will make only the AuditData property get forwarded into ConvertFrom-Json and ignore the rest of the object from Search-UnifiedAuditLog

Unable to access array variable

I am using the Invoke-Ping function (found here: https://gallery.technet.microsoft.com/scriptcenter/Invoke-Ping-Test-in-b553242a), which is working great. It creates output that looks like this:
> $Info = Invoke-Ping $ComputerNames -ErrorAction SilentlyContinue
> $Info[0..2]
Address : Machine1
IPV4Address : 10.10.44.213
IPV6Address :
ResponseTime : 0
STATUS : Responding
Address : Machine2
IPV4Address : 10.10.4.46
IPV6Address :
ResponseTime : 0
STATUS : Responding
Address : Machine3
IPV4Address : 10.10.4.58
IPV6Address :
ResponseTime : 0
STATUS : Responding
The problem I'm running into is when I try to do $Info.Address to output machine names. When I type $Info.Address I get
OverloadDefinitions
-------------------
System.Object&, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Address(int )
I'm sure it's because .Address is already defined but I don't know how to work around this and get to the actual value I need - My object's Address value. I'm sure it's simple but I'm just ignorant... What's the trick to get to my value?
use this command this may help you.
$Info | %{$_.Address}
This is an interesting one. It looks like you've found a bug in the Test-Connection cmdlet. That is what Invoke-Ping uses to ping the computers.
PetSerAl is correct. You can use ForEach to get the correct output. Alternatively you could also manually specify the item in the array that you are looking for. Example:
#Display Address of First item
$info[0].Address
#Display Address of All items
$info | Foreach {$_.Address}
#or
for ($i=0; $i -lt $info.Count; $i++) { $info[$i].Address }
Interesting, haven't run into a case of this, but it appears the root cause is that an array has an Address method.
You can verify like this: Get-Member -InputObject #(), or, with your code, Get-Member -InputObject $Info.
Why is this happening? While it's quite convenient, we're relying on a language feature that will unravel a property from an array, and properties / methods directly on the array will take precedence. This means we need to resort to the various workarounds folks have answered with.
Cheers!