Combining variables in a table - powershell

I am trying to combine two variables each containing a list of values:
cls
$Sites = Get-ADReplicationSite -Filter *
$Subnets = Get-ADReplicationSubnet -Filter *
$a = New-Object PSObject
$a | add-member Noteproperty "Site" $Sites.Name
$a | add-member Noteproperty "Subnet" $Subnets.Name
$a | format-table
My output looks like this:
Site Subnet
---- ------
{Default-First-Site-Name, SITE1, SI... {10.0.0.0/24, 20.0.0.0/24, 30.0.0.0/...
As the above does not result in a clear table I wonder where I went wrong. Preferably I would combine these two variables into a .csv file. However I am not sure on how I would give each list a Header before piping it to the Export-CSV cmdlet.

Assuming that the number of sites is equal to the number of subnets, try this:
$sites | Foreach {$i=0}{new-object pscustomobject -prop #{Site=$_;Subnet=$subnets[$i]}; $i++} | Format-Table

Related

Powershell How to include username along with processname, etc.,?

Get-NetTCPConnection | Select-Object -Property LocalAddress,LocalPort,RemoteAddress,RemotePort,State,#{name='NameofApp';expression={(Get-Process -id $_.OwningProcess).MainModule.FileVersionInfo.FileDescription}} | Format-Table -AutoSize
The above one works perfectly, Here I want to include the Username as well:
I know that Get-Process -IncludeUserName will return the UserName but I don't know how to join this in the above working command.
Using your current query, here is a simple modified approach that will solve your problem:
Get-NetTCPConnection | ForEach-Object {
$process = Get-Process -Id $_.OwningProcess -IncludeUserName
$description = $process.MainModule.FileVersionInfo.FileDescription
$username = $process.UserName
$properties = $_ | Select-Object -Property LocalAddress,LocalPort,RemoteAddress,RemotePort,State
$properties | Add-Member -Name "NameOfApp" -Type NoteProperty -Value $description
$properties | Add-Member -Name "UserName" -Type NoteProperty -Value $username
$properties
} | Format-Table -AutoSize
Explanation:
Pipe Get-NetTCPConnection through to Foreach-Object.
Get the process object with Get-Process, making sure to include User Names with the -IncludeUserName switch.
Store the descriptions and usernames in separate variables. Not necessary, but I split them up for clarity.
Get all the TCP connection properties that can be selected immediately with Select-Object into a System.Management.Automation.PSCustomObject. This uses the default pipeline variable $_ from Foreach-Object, which is basically the current item from GetNetTCPConnection. You can run Get-Help -Name about_Automatic_Variables to find out more about pipeline variables, and Get-Help -Name about_pipelines for finding out more about pipelines. Unfortunately, these Help files don't contain online versions.
Add the NameOfApp and UserName members to the object with Add-Member.
Format into a table with Format-Table and auto size columns with the -AutoSize switch.
You could also use regular foreach enumeration as well:
& {
foreach ($connection in Get-NetTCPConnection) {
$process = Get-Process -Id $connection.OwningProcess -IncludeUserName
$description = $process.MainModule.FileVersionInfo.FileDescription
$username = $process.UserName
$properties = $connection | Select-Object -Property LocalAddress,LocalPort,RemoteAddress,RemotePort,State
$properties | Add-Member -Name "NameOfApp" -Type NoteProperty -Value $description
$properties | Add-Member -Name "UserName" -Type NoteProperty -Value $username
$properties
}
} | Format-Table -AutoSize
The above is wrapping the foreach loop inside a script block, so you need to use the call operator & to run it. You can read more About Operators and About Script Blocks.

Two row header for Get-ADObject | Export-Csv?

An external system we use requires an import of an excel template. The data that is being imported can be derived from Active Directory data.
I am building a one-click solution in PowerShell 2.0 that builds this template out with current Active Directory data.
The current process I am using is Get-ADObject > select and do some reformating | Export-Csv.
The template I am trying to replicate has two header rows. Export-Csv only provides one header, based on the field name (I actually used Select-Object #{Label=,Expression=} to customize the ADObject property names).
How can I add another header row? Can I append an entry to the beginning of each ADObject property?
Header 1
Entry1
Entry2
Entry3
to
Header 1
Header 2
Entry1
Entry2
Entry3
Maybe just duplicate to 2nd header?
Get-ADObject | Select-Object Header1,#{label='Header2';expression=$_.Header1}
Or if it needs to be in same row:
$Data = Get-ADObject | additional piping
$Data.Header1 += 'Header2'
$Data | Export-CSV
Or you are trying to add Property
$Data = Get-ADObject | additional piping
[PSCustomObject]$NewData = $Data
$NewData | Add-Member -MemberType NoteProperty -Name 'MyProperty' -Value 'myvalue'
$NewData | Export-CSV
So I ended up getting what I wanted, by first converting my AD Object into a Custom object and creating second custom object with the same fields, but my headers as values. Threw them both into an array, and it writes beautifully.
$ad = Get-AdObject...
$obj1 = New-Object -TypeName PSCustomObject -property $ad
$hash = #{
'col1'='header1';
'col2'='header2';
...
}
$obj2 = New-Object -TypeName PSCustomObject -property $hash
$arr1 = #()
$arr1 += $obj2, $obj1
$arr1 | Export-csv -path...

Powershell - build a custom object with an unknown number of columns

I need to create a CSV that contains all possible emails addresses that an Active Directory user has. The CSV must be in the following format (very rigid API for where their going to be imported to):
Username | EmailAddress1 | EmailAddress2 | EmailAddressN
My script so far looks like this:
$Group = "GroupNAme
$usersObj = #()
$countMax = 0
$GetAdGroup = Get-AdGroup -Identity $Group -Properties *
[array]$members = $GetAdGroup.Members
ForEach ($member in $members) {
$currentUser = get-aduser -Identity $member `
-Properties EmailAddress, ProxyAddresses |
Where {$_.Enabled -eq "True"}
$countTemp = ($currentUser.ProxyAddresses).count
if ($countTemp -gt $countMax){ $countMax = $countTemp}
foreach ($mailAdd in $currentUser.ProxyAddresses) {
$usersOBJ += [pscustomobject]#{
'Username' = $currentUser.SamAccountName;`
'ProxyAddresses' = $mailAdd.SubString(5)
}
}
$usersOBJ | Export-CSV -NoTypeInformation C:\Export.csv
Now my existing Object spits out the Users as follows:
UserName | Emailaddress1
Username | Emailaddress2
Username | EmailsaddressN
I can't seem to make the leap into working out how to create a better object. I can get the max number of ProxyAddresses that occur but I'm not sure how to figure that into building my object and then populating the values of the $currentUser.ProxyAddresses into those columns.
I've read about Hash tables but they don't seem to fit my requirements, usually taking the form:
Username1 | Username2
Emailaddress1 | Emailaddress1
Emailaddress2 | Emailaddress2
Can anyone please point me in the right direction?
Cheers!
You just need to separate the values you're adding a bit. Add the username to a single object before the loop, then add additional properties on an as-needed basis. Finally, add the object to your array to be exported.
Try this:
...
$x = New-Object System.Object
$x | Add-Member –type NoteProperty –Name UserName –Value $currentUser.SamAccountName
$i=0
foreach ($mailAdd in $currentUser.ProxyAddresses) {
$i++
$x | Add-Member –type NoteProperty –Name "Emailaddress$i" –Value $mailAdd.SubString(5)
}
$usersOBJ += $x
Assuming you add all the users to $usersOBJ before exporting the csv, the columns should work perfectly for any number of proxy addresses.

Script output that will work on the console as well as with Export-Csv

I'm working on a basic PowerShell script that inputs a pair of dates then gets all accounts with passwords expiring between those times. I'd like to output the data to the console in a way that is compatible with Export-Csv. That way the person running the script can either just view in the console, or get a file.
Here is my script:
[CmdletBinding()]
param(
[string]$StartDate = $(throw "Enter beginning date as MM/DD/YY"),
[string]$EndDate = $(throw "Enter end date as MM/DD/YY")
)
$start = Get-Date($StartDate)
$end = Get-Date($EndDate)
$low = $start.AddDays(-150)
$high = $end.AddDays(-150)
$passusers = Get-ADUser -Filter { PasswordLastSet -gt $low -and PasswordLastSet -lt $high -and userAccountControl -ne '66048' -and userAccountControl -ne '66080' -and enabled -eq $true} -Properties PasswordLastSet,GivenName,DisplayName,mail,LastLogon | Sort-Object -Property DisplayName
$accts = #()
foreach($user in $passusers) {
$passLastSet = [string]$user.PasswordLastSet
$Expiration = (Get-Date($passLastSet)).addDays(150)
$obj = New-Object System.Object
$obj | Add-Member -MemberType NoteProperty -Name Name -Value $user.DisplayName
$obj | Add-Member -MemberType NoteProperty -Name Email -Value $user.mail
$obj | Add-Member -MemberType NoteProperty -Name Expiration -Value $expiration
$accts += $obj
}
Write-Output ($accts | Format-Table | Out-String)
This prints to the console perfectly:
Name Email Expiration
---- ----- ----------
Victor Demon demonv#nsula.edu 1/3/2016 7:16:18 AM
However when called with | Export-Csv it doesn't:
#TYPE System.String
Length
5388
I've tried multiple variations using objects, and data tables, however it seems like I can only get it to work for console or for CSV, not for both.
Replace
Write-Output ($accts | Format-Table | Out-String)
with
$accts
That way your users can run your script any way they like, e.g.
.\your_script.ps1 | Format-Table
.\your_script.ps1 | Format-List
.\your_script.ps1 | Export-Csv
.\your_script.ps1 | Out-GridView
...
Format-Table | Out-String converts your output to a single string whereas Export-Csv expects a list of objects as input (the object properties then become the columns of the CSV). If Export-Csv is fed a string, the only property is Length, so you get a CSV with one column and one record.
$accts | ConvertTo-Csv | Tee -File output.csv | ConvertFrom-Csv

Simple script to ping PCs, output table - what's wrong?

I was trying to write a simple script to ping a list of computers, and output the result in a table. I ended up doing this, which works fine:
Get-ADComputer -searchbase "OU=Materials,OU=MMC Computers,OU=REI,DC=REIDOMAIN,DC=LOCAL" -filter * | select -expand name | % {
$output = New-Object PSObject
$output | Add-Member NoteProperty "Computer name"($_)
$output | Add-Member NoteProperty "Ping result"("$($(Test-Connection $_ -count 1 -quiet).ToString())")
write $output }
However, I'd like to understand why my first two attempts didn't work, so that I can avoid making the same mistakes later. Here they are:
Script 1: See edit below
Get-ADComputer -searchbase "OU=Materials,OU=MMC Computers,OU=REI,DC=REIDOMAIN,DC=LOCAL" -filter * |
select -expand name | % { $computer = $_; $obj = "" |
select #{Name="Computer";Expression="$computer"},`
#{Name="Pingable";Expression="$($(Test-Connection $computer -count 1 -quiet).ToString())"}
$obj }
Output 1:
Computer Pingable
-----— -----—
Note: Under the table headers, this script actually prints one blank line for each computer I'm pinging.
Script 2:
$table = #{Expression={$_};Label="Computer"},#{Expression={"$($(Test-Connection $_ -count 1 -quiet).ToString())"};Label="Pingable"}
Get-ADComputer -searchbase "OU=Materials,OU=MMC Computers,OU=REI,DC=REIDOMAIN,DC=LOCAL" -filter * | select -expand name | format-table $table
Output 2:
mickeymouse
goofy
minnie
pluto
frank
This one doesn't even output a table...it just prints one computer name per line.
I'd appreciate if someone could explain what's going wrong in these two attempts. Thanks!
Edit: Got Script 1 to work.
Get-ADComputer -searchbase "OU=Materials,OU=MMC Computers,OU=REI,DC=REIDOMAIN,DC=LOCAL" -filter * |
select #{Name="Computer";Expression={$_.Name}},#{Name="Pingable";Expression={"$($(Test-Connection $_.Name -count 1 -quiet).ToString())"}};
Still curious about Script 2
In your second example, you are using the -ExpandProperty of Select-Object which effectively strips the data from the object and outputs an array of strings which format-table then outputs as a list.
See this example:
#First create the array of objects
$rawData = #( #{"Name"="First Obj"; "OtherParam"=1;}, #{"Name"="Second Obj"; "OtherParam"=2;})
$objects = $rawData | %{new-object -type psobject -prop $_}
#Just output the objects
$objects | format-table
Output:
Name OtherParam
---- ----------
First Obj 1
Second Obj 2
Now select the name property, this gives an array of objects with just a single property "name"
$objects | select name | format-table
Output:
Name
----
First Obj
Second Obj
Expand the name property, this gives an array of strings that format table just lists with no heading:
$objects | select -expand name | format-table
Output:
First Obj
Second Obj