Powershell - extract to csv from the loop - powershell

when i tried to extact results from this code
$Output = #()
foreach($emailproxy in $emailproxies)
{
if($emailproxy.Mail -like "*com" -or $emailproxy.Mail -like "*org"){ Write-Host $emailproxy.Mail}
$Output = New-Object -TypeName PSObject -Property #{
Mail = $emailproxy.Mail
} | Select-Object Mail
}
$Output | Export-Csv C:\TempDownloads\results.csv
I only get 1 result .. why is that ?

For each iteration in the loop, you are assigning (overwriting) the value directly to the $Output variable, instead of adding the value to the array.
Inside the for loop, you need to replace $Output = with $Output +=.
$Output = <new value> -> Assign <new value> to $Output variable, existing value of $Output is overwritten and lost.
$Output += <new value> is equivalent to $Output = $Output + <new value>, where <new value> and current value of $Output are first combined and then assigned to $Output.

This is because you are overwrighting the variable $output each time. You need to append properties to the psobject using add-member
Output = New-Object -TypeName Psobject
foreach($emailproxy in $emailproxies) { if($emailproxy.Mail -like "*com" -or $emailproxy.Mail -like "*org"){ Write-Host $emailproxy.Mail}
$Output | Add-Member -MemberType NoteProperty -Name "Mail" -Value $_.mail
}
$Output | Export-Csv "filepath"

Related

dynamically creating key/value of an object and exporting to CSV

After getting a search result from an LDAP Server, i need to create a pscustomobject dynamically.
The Problem here is that some of the attributes are not set for all users.
this is why i cannot create the pscustomobject the traditional way.
Name = $($item.Attributes['givenname'].GetValues('string'))
Surname = $($item.Attributes['sn'].GetValues('string'))
The Attribute Name does not exist for all users and doing this throws an error.
How can i create the pscustomobject in this case where i need to add both key and value dynamically.
Here is what i have so far:
$vals="cn","tel","email","sn","givenname","ou"
$c.Bind()
$r = New-Object System.DirectoryServices.Protocols.SearchRequest -ArgumentList $baseDN,$Filter,$scope,$attrlist
$re = $c.SendRequest($r)
foreach ($item in $re.Entries) {
foreach($attr in $vals){
if($item.Attributes.Keys -contains $attr){
$pskeys += $attr
}}
foreach($pskey in $pskeys){
$data += [pscustomobject]#{
$($pskey) = $($item.Attributes[$pskey].GetValues('string'))
}}
$pskeys = #()
}
givenname does not exist for all the users and this is why the pscustombject must be created dynamically.
I cannot use a HashTable or some kind of a List as duplicate values must be allowed. There are cases where the attributes sn and givenname are equal.
After hours of trying and failing i can only hope for the Wizards of Stackoverflow to show me how this can be achieved.
I need a pscustomobject where i can save the available attributes and skip the missing attributes dynamically. Is there a way to do this?
Regards
Try following :
$table = [System.Collections.ArrayList]::new()
foreach ($item in $re.Entries) {
$newRow = New-Object -TypeName psobject
foreach($attr in $vals){
if($item.Attributes.Keys -contains $attr){
$pskeys += $attr
}}
foreach($pskey in $pskeys){
foreach($item in $item[$pskey].Attributes.GetValues('string'))
{
$newRow | Add-Member -NotePropertyName $item.Name -NotePropertyValue $item.Value
}
}
$table.Add($newRow) | Out-Null
}
$table | Format-Table
Finally!
I have gotten it to work!
The Trick was to enclose $pskey and $item.Attributes[$pskey].GetValues('string') in $()
Without $() Add-Member was adding the properties as Arrays and not as Strings.
Here is the working Code:
$table = New-Object System.Collections.ArrayList
$c.Bind()
$r = New-Object System.DirectoryServices.Protocols.SearchRequest -ArgumentList $baseDN,$Filter,$scope,$attrlist
$re = $c.SendRequest($r)
foreach ($item in $re.Entries) {
$newRow = New-Object -TypeName psobject
foreach($attr in $vals){
if($item.Attributes.Keys -contains $attr){
$pskeys += $attr
}}
foreach($pskey in $pskeys){
$newRow | Add-Member -NotePropertyName $($pskey) -NotePropertyValue $($item.Attributes[$pskey].GetValues('string'))
}
$table.Add($newRow) | Out-Null
$pskeys = #()
}
$table | Export-Csv -Path $ExportPath -NoTypeInformation -Encoding UTF8 -Append -Delimiter ";"
Thank You jdweng for pointing me in the right direction.
$table | Format-Table on the console and the resulting CSV after the Export look flawless now.
My Problem is solved.

Array in a foreach loop

What am I doing wrong here?
The mailbox has an active an inactive mailbox so it will return two mailboxes.
However, when trying to capture the output, I am only getting the last account in the array
Note, this is a simplified version of a larger script, but kept it simple for this example.
$guid = import-csv "c:\temp\Mailboxes.csv"
$DAta = New-Object psobject
$Data | Add-Member -MemberType NoteProperty -Name alias -Value $null
$Data | Add-Member -MemberType NoteProperty -Name guid -Value $null
$mbxcol = #()
#$data = $null
foreach ($G in $Guid){
$mbx = Get-mailbox $g.alias -IncludeInactiveMailbox
$data.alias = $mbx.alias
$data.guid = $mbx.guid
$MBXCol += $Data
}
$mbxcol
As explained in comments, every array element is a reference of the same object ($Data), a simple way to demonstrate using Object.ReferenceEquals Mehod with this example:
foreach ($item in 0..10) {
$data.Alias = 'mailbox{0}' -f $item
$data.Guid = [guid]::NewGuid()
$mbxcol += $data
}
[object]::ReferenceEquals($data, $mbxcol[0]) # -> True
As for how to simplify and make your code more efficient, do not add elements (+=) to a fixed collection (#( )):
$result = (Import-Csv "c:\temp\Mailboxes.csv").Alias |
Get-Mailbox -IncludeInactiveMailbox |
Select-Object Alias, Guid
A much more simple example of your code is:
$guid = ("A","B")
$Data = New-Object psobject
$Data | Add-Member -MemberType NoteProperty -Name alias -Value $null
$mbxcol = #()
foreach ($G in $Guid){
$mbx = $g
$data.alias = $mbx
$MBXCol += $Data
}
$mbxcol
As #Santiago mentioned in his comment, $Data is a reference to an object, so each time you update it, you overwrite it, even if it is in an array. To fix this, instantiate the object each loop as follows:
$guid = ("A","B")
$mbxcol = #()
foreach ($G in $Guid){
$Data = New-Object psobject
$Data | Add-Member -MemberType NoteProperty -Name alias -Value $null
$mbx = $g
$data.alias = $mbx
$MBXCol += $Data
}
$mbxcol

Incrementing value in a loop in powershell

I would like to ask for some help regarding an incrementing value applied in the script below
For each certificate it found, a counter increments by 1, I tried usig $i=0; $i++ but I'm not getting anywhere.
$Expiry = Get-ChildItem -Path cert: -Recurse
$Rep= #()
Foreach ($cert in $Expiry)
{
if ($cert.notafter -le (get-date).Adddays(120) -AND $cert.notafter -gt (get-date))
{
$obj = New-Object PSObject
$Daysleft = $Cert.NotAfter - (get-date)
$obj | Add-Member -type NoteProperty -Name "Path" $cert.PSParentPath
$obj | Add-Member -type NoteProperty -Name "Issuer" $cert.Issuer
$obj | Add-Member -type NoteProperty -Name "NotAfter" $cert.NotAfter
$obj | Add-Member -type NoteProperty -Name "DaysLeft" $Daysleft.Days
$Rep +=$obj
}
}
My goal here is if it satisfies the condition, it will display the certificate and a counter will be plus 1. until it completes the loop then it displays the total certificates found
Hoping for your help
Thank you
You don't need a loop counter for this, or even a loop if you use Select-Object to return objects with the chosen properties like this:
# It's up to you, but personally I would use $today = (Get-Date).Date to set this reference date to midnight
$today = Get-Date
$Expiry = Get-ChildItem -Path cert: -Recurse
$Rep = $Expiry | Where-Object { $_.NotAfter -le $today.AddDays(120) -and $_.NotAfter -gt $today |
Select-Object #{Name = 'Path'; Expression = {$_.PSParentPath}},
Issuer, NotAfter,
#{Name = 'DaysLeft'; Expression = {($_.NotAfter - $today).Days}}
}
# to know howmany items you now have, use
#($Rep).Count
Note:
I'm using calculated properties in the Select-Object line to get the properties you need
By surrounding $Rep in the last line with #(), you are forcing the variable to be an array, so you can use its .Count property safely

Powershell update value in Array

I'm suspect I am going about this the wrong way and need to switch to a hash table but is it possible to update a specific value in an Array?
The script retrieves the cluster nodes and stores the data in a array, then proceeds to reboot each one, once rebooted I want to update the reboot 'column' value in the array to 1.
$Array=#()
$Cluster = Get-ClusterNode
foreach ($Node in $Cluster)
{
$item = New-Object PSObject
$item | Add-Member -type NoteProperty -Name 'Node' -Value $Node.Name
$item | Add-Member -type NoteProperty -Name 'State' -Value $Node.State
$item | Add-Member -type NoteProperty -Name 'Rebooted' -Value "0"
$Array += $item
}
foreach ($row in $Array | Where { $Array.Rebooted -eq "0" })
{
Reboot-Function -Node $row.Node
$Array.Rebooted += 1 | Where-Object {$Array.Node -eq $row.Node}
}
$Array
You need to rewrite the Where-Object statement in the second loop slightly (use $_ to refer to the current pipeline object), and then simply update the current object via the $row variable inside the loop body:
foreach ($row in $Array | Where { $_.Rebooted -eq "0" })
{
Reboot-Function -Node $row.Node
$row.Rebooted = '1'
}

Trying to create a custom object list? hash? - Unsure

I'm trying trying to get two properties from two separate commands and add them to a variable to be able to further evaluate.
I was told a custom object would work...
Clear-Host
Add-PSSnapin citrix* -ErrorAction SilentlyContinue
$DRSrvs = Get-XAServer drptsw00* | select -ExpandProperty servername
$hash = $null
$hash = #{}
foreach ($DR in $DRSrvs) {
$hash = New-Object PsObject -Property #{
servername = $DR
Logins = (Get-XALoadEvaluator -ServerName $DR).LoadEvaluatorName
}
}
A hashtable is for mapping (unique) keys to values. If you need to map different servernames to login names use a hashtable, otherwise use custom objects. Either way you need to handle the data structures correctly.
Hashtable:
$hash = #{}
foreach ($DR in $DRSrvs) {
$hash[$DR] = (Get-XALoadEvaluator -ServerName $DR).LoadEvaluatorName
}
Custom object list:
$list = foreach ($DR in $DRSrvs) {
New-Object PsObject -Property #{
servername = $DR
Logins = (Get-XALoadEvaluator -ServerName $DR).LoadEvaluatorName
}
}
Assigning something to a variable in a loop replaces the previous value in that variable with each iteration, leaving you with just the last value after the loop finishes.
I used this method and got a very clean output. Citrix SDK for Powershell if very funny and has lots of gotchas.
Clear-Host
Add-PSSnapin citrix* -ErrorAction SilentlyContinue
$OutputData = $null
$OutputData = #()
$Srvs = Get-XAServer Srv123* | Select-Object -ExpandProperty ServerName
$object = New-Object PSObject
Add-Member -InputObject $object -MemberType NoteProperty -Name Servername -Value ""
Add-Member -InputObject $object -MemberType NoteProperty -Name LoadEval -Value ""
foreach ($Srv in $Srvs) {
$servername= $Srv
$LoadEval = ((Get-XALoadEvaluator -ServerName $Srv).LoadEvaluatorName)
$appObject = New-Object System.Object
$appObject |
Add-Member -MemberType NoteProperty -Name "ServerName" -Value $servername -PassThru |
Add-Member -MemberType NoteProperty -Name "LoadEval" -Value $LoadEval
$outputData += $appObject
}