ForEach-Object OutString, Powershell Awk Equivalents - powershell

I'm a long time Bash enthusiast trying to get my bearings with Powershell. I'm trying to do something that could easily be accomplished with Awk, but I can't seem to find a solution in Powershell documentation. I'm essentially trying to select the third value from the output of the command delimited by /
Get-ADOrganizationalUnit -Properties CanonicalName -Filter * | Select-Object -ExpandProperty CanonicalName | Select-String ".*/Example/.*"
example.local/Example/ExampleOU1
example.local/Example/ExampleOU2
I just want to select the last value shown here. In Bash land this could easily be accomplished by an awk -F "/" '{print $3}' however I'm struggling to find the equivalent in Powershell. I found Out-String | %{ $_.Split('/')[2]; }' which is nice, but only works if there's one object. I'm assuming I need to ForEach-Object, then convert to a string, then split, but I'm not sure how.

I almost never use out-string. Canonicalname is a property of the object, so you need to reference that property. This would work:
[pscustomobject]#{canonicalname = 'example.local/Example/ExampleOU1'} |
% { $_.canonicalname.Split('/')[2] }
ExampleOU1
There's also -split which uses regex:
[pscustomobject]#{canonicalname = 'example.local/Example/ExampleOU1'} |
% { ($_.canonicalname -split '/')[2] }
Paths come up so often there's a command for it:
[pscustomobject]#{canonicalname = 'example.local/Example/ExampleOU1'} |
% { split-path -leaf $_.canonicalname }

Related

Need to split (cutout a part of) the result of a powershell command into a CSV

I have a command that spits outs Active Directory SamAccountName, Description, Distinguished name into a CSV. My issue is that I only need the part of the distinguished name after the user name. I know this is conceptually simple, but I don't know enough about using Splits to get the results.
Here is my command:
get-content users.txt | get-aduser -pr
SamAccountName,Description,DistinguishedName | select
SamAccountName,Description,DistinguishedName | Export-Csv users.csv
Here is my output:
Line1-- "user1","user1 description","CN=Lastname\, Firstname(user1),OU=OU2,OU=OU1,OU=Site-1,OU=Accounts_User,DC=domain,DC=company,DC=com"
Line2--- "user2","user2 description","CN=Lastname\, Firstname,OU=OU1,OU=Site-2,OU=Accounts_User,DC=domain,DC=company,DC=com"
What I need is to drop the CN=username2(username2), part of the result. So that my output looks like:
"user2","user2 description","OU=OU1,OU=Site-2,OU=Accounts_User,DC=domain,DC=company,DC=com"
You can use Select-Object dynamic expressions to manipulate a property and return that as part of your results, by constructing a select expression like:
Select-Object #{Name="NewName"; Expression={..any scriptblock..}}
In your case, I would remove the unwanted string part with a regex, by matching the CN=([^=]*),OU= and leaving only the OU= part only:
$_.DistinguishedName -ireplace "CN=([^=]*),OU=","OU="
So Altogether:
get-content users.txt |
get-aduser -pr SamAccountName,Description,DistinguishedName |
Select SamAccountName,Description, #{Name="NewDN"; Expression={$_.DistinguishedName -ireplace "CN=([^=]*),OU=","OU="}} |
Export-Csv users.csv

Formatting variable with 2 outputs

Code:
$adgroups = Get-ADPrincipalGroupMembership $tag$ | select -ExpandProperty Name | Sort | Select-String "iSite"
Output:
DFSR Managed iSite Enterprise 4.4.542.2 WSA_Rad_A
DFSR Managed iSite Radiology 4.4.516.27 WSA_Rad_A
Basically one command generates two items (output using $variable | out-file C:\file.txt -Append) and when I go to open these in excel they format as one line like this:
DFSR Managed iSite Enterprise 4.4.542.2 WSA_Rad_A DFSR Managed iSite Radiology 4.4.516.27 WSA_Rad_A
Is there a way to break it up // add a new line after each item but still keep them both inside one variable?
Get-ADPrincipalGroupMembership $tag$ | select -ExpandProperty Name | Sort | Select-String "iSite" | ConvertTo-Csv -NoTypeInformation | Out-File C~\Desktop\Sites.csv
I would break up your request a bit.
First, you're using Select -Expand, which is going to discard all of the properties and only return the values for each object's Name. This is a problem because when you export it as a CSV, you're not going to have a heading. I think the lack of header is ultimately leading to the issue you're facing here.
Try this instead:
$adgroups = Get-ADPrincipalGroupMembership $tag$ | Where Name -like "*iSite*" |
select Name | Export-Csv c:\pathto\YourCsv.Csv
Finally, I don't think Select-String is doing you any favors. You could instead use the -like operator.

Return first matching line

I have an XML command that returns a list of URLs, example
PS > $xml.rss.channel.item.link
http://example.com/20140704.exe
http://example.com/20140704.tar.xz
http://example.com/20140624.exe
http://example.com/20140624.tar.xz
http://example.com/20140507.tar.xz
From this list, I would like to return the first .tar.xz line. I have this
command
$xml.rss.channel.item.link | ? {$_ -match '.tar.xz'} | select -first 1
But I would prefer a command with only one pipe if possible.
You don't need a pipe at all:
(Select-Xml -Xml $xml -XPath "(//link[contains(.,'.tar.xz')])[1]").Node.InnerText
Note: XPath is case-sensitive. If that is an issue, you can use a trick with translate() function and force it to ignore the case.
A different way using two pipes
$xml.rss.channel.item.link | Select-String .tar.xz | select -first 1
One pipe
($xml.rss.channel.item.link | Select-String .tar.xz)[0]

Powershell - Get-DistributionGroup exporting to csv issue

The below command will output the correct information to the screen, however when exporting to a csv file it looks nothing like what is shown on the screen. I have been able to export with other cmdlets, Get-DistributionGroup seems to corrupt the data when using with export.csv.
Outputting to screen works great!
Get-DistributionGroup | Where {$_.emailaddresses -like "*#adomain.com*"} | FT Name,Alias,EmailAddresses
Exporting to csv doesnt work correctly
Get-DistributionGroup | Where {$_.emailaddresses -like "*#adomain.com*"} | FT Name,Alias,EmailAddresses | Export-csv C:/thisis.csv
Instead of Format-Table (alias: ft) you should use Select-Object. Export-Csv expects objects as input, not formating instructions.
Format-Table, by definition, will convert objects to something that looks well in your output, but it's one way trip: you loose original objects as a part of the process.
Select-Object on the other hand can create objects with subset of properties, so that cmdlets like Export-Csv can still use data from original source.
EDIT
Thing I missed originally: you try to export a property that is a collection (EmailAddresses). That won't work unless you 'flatten' the collection first:
Get-DistributionGroup | Where {$_.emailaddresses -like "*#adomain.com*"} | select Name,Alias, #{
Name = 'EmailAddresses'
Expression = { $_.EmailAddresses -join '|' }
}
Thank you the answer has been resolved.
BartekB's answer
Get-DistributionGroup | Where {$.emailaddresses -like "*#adomain.com*"} | select Name,Alias, #{
Name = 'EmailAddresses'
Expression = { $.EmailAddresses -join '|' }
}

PowerShell: Format-Table without headers

In a PowerShell script, I have some objects that I pass to the Format-Table CmdLet.
The output of my script looks like this:
Something...
Operation AttributeName AttributeValue
--------- ------------- --------------
Delete Member John Doe
Something else...
Since the meaning of the fields is pretty self-explanatory, I would like to remove the headers, the '---' separators and the blank lines at the beginning and at the end from the output of Format-Table.
I don't think that the CmdLet supports this (or at least if there's a parameter to do this I couldn't find it).
What would the best way to leave only the lines with the actual values from the output of Format-Table?
Try the -HideTableHeaders parameter to Format-Table:
gci | ft -HideTableHeaders
(I'm using PowerShell v2. I don't know if this was in v1.)
Try -ExpandProperty. For example, I use this for sending the clean variable to Out-Gridview -PassThru , otherwise the variable has the header info stored. Note that these aren't great if you want to return more than one property.
An example:
Get-ADUser -filter * | select name -expandproperty name
Alternatively, you could do this:
(Get-ADUser -filter * ).name
The -HideTableHeaders parameter unfortunately still causes the empty lines to be printed (and table headers appearently are still considered for column width). The only way I know that could reliably work here would be to format the output yourself:
| % { '{0,10} {1,20} {2,20}' -f $_.Operation,$_.AttributeName,$_.AttributeValue }
Here is how I solve this. I just pipe the output to Out-String and then pass that output to the .NET Trim function:
(gci | ft -HideTableHeaders | Out-String).Trim()
This will strip out the line breaks before and after the table.
You can also use TrimStart to just take care of the header's line break if you still want the trailing line breaks.
(gci | ft -HideTableHeaders | Out-String).TrimStart()
Another approach is to use ForEach-Object to project individual items to a string and then use the Out-String CmdLet to project the final results to a string or string array:
gci Microsoft.PowerShell.Core\Registry::HKEY_CLASSES_ROOT\CID | foreach { "CID Key {0}" -f $_.Name } | Out-String
#Result: One multi-line string equal to:
#"
CID Key HKEY_CLASSES_ROOT\CID\2a621c8a-7d4b-4d7b-ad60-a957fd70b0d0
CID Key HKEY_CLASSES_ROOT\CID\2ec6f5b2-8cdc-461e-9157-ffa84c11ba7d
CID Key HKEY_CLASSES_ROOT\CID\5da2ceaf-bc35-46e0-aabd-bd826023359b
CID Key HKEY_CLASSES_ROOT\CID\d13ad82e-d4fb-495f-9b78-01d2946e6426
"#
gci Microsoft.PowerShell.Core\Registry::HKEY_CLASSES_ROOT\CID | foreach { "CID Key {0}" -f $_.Name } | Out-String -Stream
#Result: An array of single line strings equal to:
#(
"CID Key HKEY_CLASSES_ROOT\CID\2a621c8a-7d4b-4d7b-ad60-a957fd70b0d0",
"CID Key HKEY_CLASSES_ROOT\CID\2ec6f5b2-8cdc-461e-9157-ffa84c11ba7d",
"CID Key HKEY_CLASSES_ROOT\CID\5da2ceaf-bc35-46e0-aabd-bd826023359b",
"CID Key HKEY_CLASSES_ROOT\CID\d13ad82e-d4fb-495f-9b78-01d2946e6426")
The benefit of this approach is that you can store the result to a variable and it will NOT have any empty lines.
I know it's 2 years late, but these answers helped me to formulate a filter function to output objects and trim the resulting strings. Since I have to format everything into a string in my final solution I went about things a little differently.
Long-hand, my problem is very similar, and looks a bit like this
$verbosepreference="Continue"
write-verbose (ls | ft | out-string) # this generated too many blank lines
Here is my example:
ls | Out-Verbose # out-verbose formats the (pipelined) object(s) and then trims blanks
My Out-Verbose function looks like this:
filter Out-Verbose{
Param([parameter(valuefrompipeline=$true)][PSObject[]]$InputObject,
[scriptblock]$script={write-verbose "$_"})
Begin {
$val=#()
}
Process {
$val += $inputobject
}
End {
$val | ft -autosize -wrap|out-string |%{$_.split("`r`n")} |?{$_.length} |%{$script.Invoke()}
}
}
Note1: This solution will not scale to like millions of objects(it does not handle the pipeline serially)
Note2: You can still add a -noheaddings option.
If you are wondering why I used a scriptblock here, that's to allow overloading like to send to disk-file or other output streams.