Combine columns from 2 CSV files - powershell

This seems very basic yet I can't find or figure out anywhere
I have 2 CSV files I would like to create a new one that will have matched columns.
Huge.csv
"Share","Group","Username","Name","LogonScript"
"\\SHARE\TEST","Group Test","administrator","Administrator name","(no-script)"
"\\SHARE\TEST","Group Test","user1","user name1","logon.bat"
"\\SHARE\TEST","Group Test","user2","user name2","logon.bat"
Little.csv
"Username","Computer","NetworkDrives"
administrator,PC100,M:\\share\it#N:\\share\test
user2,PC102,M:\\share\it#N:\\share\test
Desired output:
output.csv
"Share","Group","Username","Name","LogonScript","Computer","NetworkDrives"
"\\SHARE\TEST","Group Test","administrator","Administrator name","(no-script)",PC100,M:\\share\it#N:\\share\test
"\\SHARE\TEST","Group Test","user1","user name1","logon.bat",,
"\\SHARE\TEST","Group Test","user2","user name2","logon.bat",PC102,M:\\share\it#N:\\share\test
Here's the code I'm working with:
$HugeFile = Import-Csv -Path .\Huge.csv
$LittleFile = Import-Csv -Path .\Little.csv
ForEach ($entryh in $HugeFile) {
$o | add-member NoteProperty -Name "Share" -Value ($entryh.Share)
$o | add-member NoteProperty -Name "Group" -Value ($entryh.Group)
$o | add-member NoteProperty -Name "Username" -Value ($entryh.Username)
$o | add-member NoteProperty -Name "Name" -Value ($entryh.Name)
$o | add-member NoteProperty -Name "LogonScript" -Value
($entryhu.LogonScript)
ForEach ($entryl in $LittleFile) {
If ($($entryh.Username) -eq $($entryl.Username)) {
$o | add-member NoteProperty -Name "Computer" -Value ""
($entryl.Computer)
$o | add-member NoteProperty -Name "NetworkDrives" -Value ""
($entryl.NetworkDrives)
} Else {
$o | add-member NoteProperty -Name "Computer" -Value "," -Force
$o | add-member NoteProperty -Name "NetworkDrives" -Value "," -Force
}
$o | Export-Csv -NoTypeInformation .\output.csv
}
}
}
My code is not working. :/
My second problem is that I am thinking if there a better option because for each "Username" in Huge.csv I have to compare with "Username" in Little.csv.
Maybe creating a hashtable could be more optimal.
Concat Computer and Network a create a value?
Like:
key Computer+NetworkDrive
----------- ---------------------
administrator PC100,M:\\share\it#N:\\share\test
user2 PC102,M:\\share\it#N:\\share\test
Thanks a lot!
Edit
Thanks #Ansgar-Wiechers

Yes, a hashtable is probably the best way to go about this. I'd do it like this:
$additionalData = #{}
Import-Csv .\Little.csv | % {
$additionalData[$_.Username] = $_.Computer, $_.NetworkDrives
}
Import-Csv .\Huge.csv `
| select Share, Group, Username, Name, LogonScript, #{n='Computer';e={}},
#{n='NetworkDrives';e={}} `
| % {
if ( $additionalData.ContainsKey($_.Username) ) {
$_.Computer = $additionalData[$_.Username][0]
$_.NetworkDrives = $additionalData[$_.Username][1]
}
$_
} | Export-Csv -NoTypeInformation .\output.csv
Or, following #mjolinor's suggestion, using separate hashtables for computers and network drives:
$computers = #{}
$netDrives = #{}
Import-Csv .\Little.csv | % {
$computers[$_.Username] = $_.Computer
$netDrives[$_.Username] = $_.NetworkDrives
}
Import-Csv .\Huge.csv `
| select Share, Group, Username, Name, LogonScript, #{n='Computer';e={}},
#{n='NetworkDrives';e={}} `
| % {
if ( $computers.ContainsKey($_.Username) ) {
$_.Computer = $computers[$_.Username]
}
if ( $netDrives.ContainsKey($_.Username) ) {
$_.NetworkDrives = $netDrives[$_.Username]
}
$_
} | Export-Csv -NoTypeInformation .\output.csv

Related

How to Capture Cluster info Remotely from a non-Clustered Node

I've been banging my head on this for a few days now, and I just can't figure out the best way to do it. I've got a script where I collect a bunch of data and output it to an html file (using PSWriteHTML Module, which is where the New-HTMLTable at the end comes from).
I've piecemealed the script together over time so I can gather the data from multiple servers at once, and for the most part, it all works great. As I've added data to the script to collect new info, there's a few parts that I just can't get to work right remotely. I know the piecemeal approach has left me with some redundant code, but I'm just trying to make it all work right before I re-write it again to clean it up, so my apologies for its current state.
The following code works great when I run the script from a server in a Windows Cluster, but I want things to work from any server, not necessarily a Cluster Node.
Here's orig code for this section:
try
{
$ClusterIPInfo = Invoke-command -computer $Computer {
Get-Cluster | Get-ClusterResource | %{
$_ | select Name,
#{ Name = "Address"; Expression = { $_ | Get-ClusterParameter -Name Address -ErrorAction SilentlyContinue | select -ExpandProperty Value } },
#{ Name = "SubnetMask"; Expression = { $_ | Get-ClusterParameter -Name SubnetMask -ErrorAction SilentlyContinue | select -ExpandProperty Value } }
}
} | Select -Property * -ExcludeProperty PSComputerName, RunSpaceID, PSShowComputerName
$ClusterResourceInfo = Invoke-command -computer $Computer {
Get-ClusterResource | Select Cluster, Name, State, ResourceType, OwnerGroup, OwnerNode, ID, IsCoreResource, IsNetworkClassResource, IsStorageClassResource | Sort-Object -Property OwnerGroup, Name
} | Select -Property * -ExcludeProperty PSComputerName, RunSpaceID, PSShowComputerName
$ResourceInfo = #()
foreach ($rec in $ClusterResourceInfo)
{
$Owner = (Get-ClusterResource | Sort-Object -Property OwnerGroup, Name | Get-ClusterOwnerNode | %{
$_ | select #{ Name = "Name"; Expression = { $_.ClusterObject } },
#{ Name = "PossibleOwners"; Expression = { $_.OwnerNodes } }
} | Where { $_.Name -eq $rec.Name }).PossibleOwners
$Dependency = (Get-ClusterResource | Sort-Object -Property OwnerGroup, Name | Get-ClusterResourceDependency | %{
$_ | select #{ Name = "Name"; Expression = { $_.Resource } },
#{ Name = "Dependency"; Expression = { $_ | Select-Object -ExpandProperty "DependencyExpression" } }
} | Where { $_.Name -eq $rec.Name }).Dependency
$address = ($ClusterIPInfo | Where { $_.Name -eq $rec.Name }).Address
$subnetmask = ($ClusterIPInfo | Where { $_.Name -eq $rec.Name }).SubnetMask
$recObj = New-Object PSObject
$recObj | Add-Member NoteProperty -Name "Cluster" -Value $rec.Cluster
$recObj | Add-Member NoteProperty -Name "Name" -Value $rec.Name
$recObj | Add-Member NoteProperty -Name "State" -Value $rec.State
$recObj | Add-Member NoteProperty -Name "Resource Type" -Value $rec.ResourceType
$recObj | Add-Member NoteProperty -Name "Owner Group" -Value $rec.OwnerGroup
$recObj | Add-Member NoteProperty -Name "Owner Node" -Value $rec.OwnerNode
$recObj | Add-Member NoteProperty -Name "Possible Owners" -Value $Owner
$recObj | Add-Member NoteProperty -Name "Dependency" -Value $Dependency
$recObj | Add-Member NoteProperty -Name "IP Address" -Value $address
$recObj | Add-Member NoteProperty -Name "Subnet Mask" -Value $subnetmask
$recObj | Add-Member NoteProperty -Name "Is Core Resource" -Value $rec.IsCoreResource
$recObj | Add-Member NoteProperty -Name "Is Network Resource" -Value $rec.IsNetworkClassResource
$recObj | Add-Member NoteProperty -Name "Is Storage Resource" -Value $rec.IsStorageClassResource
$ResourceInfo += $recObj
}
New-HTMLTable -DataTable $ResourceInfo -HideFooter -HideButtons -DisableSearch
The parts that don't work correctly remotely are the Dependency and PossibleOwners. I know the reason it doesn't work is because when the server running the script isn't a Cluster Node, it doesn't recognize the command under the Foreach loop Get-ClusterResource. But I just can't figure out how to make those pass correctly from within the Foreach loop, but still use the info from $ClusterResourceInfo.
I've re-written this a hundred different ways, i.e. make a single Invoke-command with basically one big Get-Cluster variable (couldn't get it to capture the Dependency/PossOwners, always $null), splitting up the Dependency and PossOwners to their own separate Invoke-Command (best I can get it to do is display System.Object[], or when I did get it to display, it captured ALL of the Dependencies for all objects and displayed on every line instead of splitting it up correctly).
I've tried every possible way I can think of or found online, but just can't get it to work correctly remotely.
Here's how the orig code above outputs (which is what I want, but I just want to fix it so it works remotely):
I am desperately hoping for some brilliance or guidance to set me on the right track. I tried so many ways, but just never quite got it where it needs to be, so any help is most appreciated and welcome. Thanks.
Couple of things i can suggest.
The "Get-ClusterResource" cmdlet fails because it is not installed on the server.
You may try to load the Failover cluster module using Import-Module, and if it fails (on a non-cluster Node), you can add the Failover Cluster Module for Windows PowerShell Feature, using the following PowerShell cmd:
Add-WindowsFeature RSAT-Clustering-PowerShell
You may try connecting to to the remote cluster node where the resource is hosted, using WMI ?
You have enough info about the resource to be able to write a filtered WMI query.
So the piecemeal approach is what got me in trouble. In trying to merge things together, I kept breaking it (mainly because I think had doubled up the %{}). So instead of merging, I just replicated the parts that were already working as intended.
Ultimately this code worked fine:
$ClusterInfo = Invoke-command -computer $Computer {
Get-Cluster | Get-ClusterResource | %{
$_ | select Name,
#{ Name = "Address"; Expression = { $_ | Get-ClusterParameter -Name Address -ErrorAction SilentlyContinue | select -ExpandProperty Value } },
#{ Name = "SubnetMask"; Expression = { $_ | Get-ClusterParameter -Name SubnetMask -ErrorAction SilentlyContinue | select -ExpandProperty Value } },
#{ Name = "PossibleOwners"; Expression = { $_ | Get-ClusterOwnerNode | select OwnerNodes | select -ExpandProperty OwnerNodes } },
#{ Name = "Dependency"; Expression = { $_ | Get-ClusterResourceDependency | select -ExpandProperty "DependencyExpression" } }
}
} | Select -Property * -ExcludeProperty PSComputerName, RunSpaceID, PSShowComputerName
$ClusterResourceInfo = Invoke-command -computer $Computer {
Get-ClusterResource | Select Cluster, Name, State, ResourceType, OwnerGroup, OwnerNode, IsCoreResource, IsNetworkClassResource, IsStorageClassResource | Sort-Object -Property OwnerGroup, Name
} | Select -Property * -ExcludeProperty PSComputerName, RunSpaceID, PSShowComputerName
$ResourceInfo = #()
foreach ($rec in $ClusterResourceInfo)
{
$Owner = ($ClusterInfo | Where { $_.Name -eq $rec.Name }).PossibleOwners
$Dependency = ($ClusterInfo | Where { $_.Name -eq $rec.Name }).Dependency
$address = ($ClusterInfo | Where { $_.Name -eq $rec.Name }).Address
$subnetmask = ($ClusterInfo | Where { $_.Name -eq $rec.Name }).SubnetMask
$recObj = New-Object PSObject
$recObj | Add-Member NoteProperty -Name "Cluster" -Value $rec.Cluster
$recObj | Add-Member NoteProperty -Name "Name" -Value $rec.Name
$recObj | Add-Member NoteProperty -Name "State" -Value $rec.State
$recObj | Add-Member NoteProperty -Name "Resource Type" -Value $rec.ResourceType
$recObj | Add-Member NoteProperty -Name "Owner Group" -Value $rec.OwnerGroup
$recObj | Add-Member NoteProperty -Name "Owner Node" -Value $rec.OwnerNode
$recObj | Add-Member NoteProperty -Name "Possible Owners" -Value $Owner
$recObj | Add-Member NoteProperty -Name "Dependency" -Value $Dependency
$recObj | Add-Member NoteProperty -Name "IP Address" -Value $address
$recObj | Add-Member NoteProperty -Name "Subnet Mask" -Value $subnetmask
$recObj | Add-Member NoteProperty -Name "Is Core Resource" -Value $rec.IsCoreResource
$recObj | Add-Member NoteProperty -Name "Is Network Resource" -Value $rec.IsNetworkClassResource
$recObj | Add-Member NoteProperty -Name "Is Storage Resource" -Value $rec.IsStorageClassResource
$ResourceInfo += $recObj
}
New-HTMLTable -DataTable $ResourceInfo -HideFooter -HideButtons -DisableSearch

Powershell custom append object to csv file

I'm trying to output a custom object to a csv formatted text file as I loop through a for each. One object per line.
But nothing is written to the file.
Is it something with types to be converted ?
$rechten = Get-ADGroupMember -Identity $v -Recursive -ERRORACTION silentlycontinue | Get-ADUser -Property DisplayName -ERRORACTION silentlycontinue | Select-Object Name
Write-Host -ForegroundColor Yellow "ADgroup $v wordt uitgevlooid."
foreach ($rechtenhouder in $rechten) {
$objResults = New-Object PSObject
$objResults | Add-Member -MemberType NoteProperty -Name DirectoryPath -Value $objPath
$objResults | Add-Member -MemberType NoteProperty -Name Identity -Value $rechtenhouder.name
$objResults | Add-Member -MemberType NoteProperty -Name Systemrights -Value $accessRight.FileSystemRights
$objResults | Add-Member -MemberType NoteProperty -Name systemrightstype -Value $accessRight.accesscontroltype
$objResults | Add-Member -MemberType NoteProperty -Name isinherited -Value $accessRight.isinherited
$objResults | Add-Member -MemberType NoteProperty -Name inheritanceflags -Value $accessRight.inheritanceflags
$objResults | Add-Member -MemberType NoteProperty -Name rulesprotected -Value $objACL.areaccessrulesprotected
$objResults | Add-Member -MemberType NoteProperty -Name Adtype -Value "User"
$arrResults += $objResults
Add-Content $exportpathtxtappend $objresults
}
For your specific use exporting all objects at once or in batches would be the most efficient, but there are times were it would make sense to export a record one at a time to a CSV file which is what led me to this question, so I want to post my solution.
Use Export-CSV -Append to continually add to the end of a csv file.
foreach ($rechtenhouder in $rechten) {
$objResults = New-Object PSObject -Property #{
DirectoryPath = $objPath;
Identity = $rechtenhouder.name;
Systemrights = $accessRight.FileSystemRights;
systemrightstype = $accessRight.accesscontroltype;
isinherited = $accessRight.isinherited;
inheritanceflags = $accessRight.inheritanceflags;
rulesprotected = $objACL.areaccessrulesprotected;
Adtype = "User";
}
$objResults | Export-CSV $csvPath -Append -NoTypeInformation
}
This is useful if you are continually polling at set time intervals, but less so if you are iterating over a collection of objects, just export them all at once. For example, I would use this method of exporting for a script like below:
while($true){
$procs = Get-Process | Select-Object Name,CPU
$procs | Add-Member -type NoteProperty -Name "Timestamp" -Value $(Get-Date)
$procs | Export-CSV $csvPath -Append -NoTypeInformation
sleep -Seconds 60
}
First, I suggest you to create your object in a decent smarter way:
foreach ($rechtenhouder in $rechten) {
$objResults = New-Object PSObject -Property #{
DirectoryPath = $objPath;
Identity = $rechtenhouder.name;
Systemrights = $accessRight.FileSystemRights;
systemrightstype = $accessRight.accesscontroltype;
isinherited = $accessRight.isinherited;
inheritanceflags = $accessRight.inheritanceflags;
rulesprotected = $objACL.areaccessrulesprotected;
Adtype = "User";
}
$arrResults += $objResults
}
With this done, your $arrResults now contains your objects. This can easily exported to CSV files with PowerShells builtin Export-CSV:
$arrResults | Export-Csv -Path "C:/temp/text.csv"
Using Add-Content on every loop iteration is IMHO ineffective regarding performance. If your script runs for a long time and you want to save your current state in intervals, you could e.g. start an asynchronous job - let's say every 10th iteration - exporting your current array:
$i = 0
foreach ($rechtenhouder in $rechten) {
$objResults = New-Object PSObject -Property #{
DirectoryPath = $objPath;
Identity = $rechtenhouder.name;
Systemrights = $accessRight.FileSystemRights;
systemrightstype = $accessRight.accesscontroltype;
isinherited = $accessRight.isinherited;
inheritanceflags = $accessRight.inheritanceflags;
rulesprotected = $objACL.areaccessrulesprotected;
Adtype = "User";
}
$arrResults += $objResults
if ($i % 10 -eq 0) {
Start-Job -ScriptBlock {
param($T, $Path)
$T | Export-Csv -Path $Path
} -ArgumentList #($arrTest, "Path/to/script")
}
$i++
}

powershell script to return all forwarding rules in org

I need to pull all forwarding rules for an exchange online environment, and output them to a csv. this sounds simple, but I have an additional caveat. there are 23,000 mailboxes in the org.
I was able to write the script I needed, it outputted the data, but it timed out.
then I was able to break out only certain mailboxes that were critical (11,000) but I was still timing out in powershell.
so finally, I found an article that detailed breaking up a script into blocks of 1,000, and running numerous sessions. and runs! it runs without timing out.
but it doesn't output to the csv anymore.
since my script has gone through several iterations, I'm pretty sure that my problem is the way I'm storing, or outputting the array, but for all my staring at this, I cant figure it out. short of asking the doc for a prescription of Adderall, I figured id ask here. below is the offending script.
the aliaslist.csv that it mentions is just a csv with a list of aliases for 11,000 mailboxes. if you would like to run your own tests, you can adjust $pagesize down and paste a few mailboxes into a csv called aliaslist, stored in c:\temp
Function New-O365ExchangeSession()
{
param(
[parameter(mandatory=$true)]
$365master)
#close any old remote session
Get-PSSession | Remove-PSSession -Confirm:$false
#start a new office 365 remote session
$365session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://outlook.office365.com/powershell-liveid/" -Credential $365master -Authentication Basic -AllowRedirection
$office365 = Import-PSSession $365session
}
#set input variables
$path = "C:\temp"
$InputFile = aliaslist.csv"
$UserEmail = "admin#domain.com"
#set variables for csv usage
$Offset = 0;
$PageSize = 1000;
$MbxMax = (Import-Csv "$path/$InputFile").count
#Loop in the list and retrieve the device’s information
$file = “c:\temp\office365-$((get-date).tostring(“yyyy-MM-dd”)).csv”
$365master = get-credential $UserEmail
New-O365ExchangeSession $365master
# call the office365 remote connection function
do{
$mbxlist=#(import-csv "$path/$InputFile"|select-object -skip $Offset -First $PageSize)
"Process entry $($Offset) to $($Offset+$PageSize)"
#end csv input count reference
ForEach($mbx in $MbxList)
{
#Write to Host
"start Processing $($mbx.alias)"
#end Write to host,
#Check rules
$rules = Get-InboxRule -mailbox $_.alias | ? {$_.RedirectTo -ne $null -or $_.ForwardTo -ne $null -or $_.ForwardAsAttachmentTo -ne $null}
If ($rules -ne $null)
{
$rules | % {
#check for forwardAsAttachments
If ($_.ForwardAsAttachmentTo -ne $null)
{
$obj = New-Object system.object
$obj | Add-Member -name "NetID" -Value $_.alias -MemberType NoteProperty
$obj | Add-Member -name "ForwardType" -Value "Forward As Attachment Rule" -MemberType NoteProperty
$obj | Add-Member -name "ForwardAddress" -Value $_.forwardAsAttachmentTo -MemberType NoteProperty
$obj | Add-Member -name "Enabled" -Value $_.Enabled -MemberType NoteProperty
$obj | Add-Member -name "Description" -Value $f -MemberType NoteProperty
If (Test-Path $file)
{
$mbx.alias + ”,” + ($obj | ConvertTo-Csv)[2] | Out-File $file –Append
}
Else
{
$obj | Export-Csv $file -Encoding ASCII -notypeinformation
}
}
$obj = $null
#check for redirects
If ($_.redirectto -ne $null)
{
$obj = New-Object system.object
$obj | Add-Member -name "NetID" -Value $_.alias -MemberType NoteProperty
$obj | Add-Member -name "ForwardType" -Value "Redirct Rule" -MemberType NoteProperty
$obj | Add-Member -name "ForwardAddress" -Value $_.redirectto -MemberType NoteProperty
$obj | Add-Member -name "Enabled" -Value $_.Enabled -MemberType NoteProperty
$obj | Add-Member -name "Description" -Value $c -MemberType NoteProperty
If (Test-Path $file)
{
$mbx.alias + ”,” + ($obj | ConvertTo-Csv)[2] | Out-File $file –Append
}
Else
{
$obj | Export-Csv $file -Encoding ASCII -notypeinformation
}
}
$obj = $null
#check for forwards
If ($_.ForwardTo -ne $null)
{
$obj = New-Object system.object
$obj | Add-Member -name "NetID" -Value $_.alias -MemberType NoteProperty
$obj | Add-Member -name "ForwardType" -Value "Forward Rule" -MemberType NoteProperty
$obj | Add-Member -name "ForwardAddress" -Value $_.forwardto -MemberType NoteProperty
$obj | Add-Member -name "Enabled" -Value $_.Enabled -MemberType NoteProperty
$obj | Add-Member -name "Description" -Value $f -MemberType NoteProperty
If (Test-Path $file)
{
($obj | ConvertTo-Csv)[2] | Out-File $file –Append
}
Else
{
$obj | Export-Csv $file -Encoding ASCII -notypeinformation
}
}
$obj = $null
}
}
}
#increment the start point for the next chunk
$Offset+=$PageSize
#Call the office365 remote session function to close the current one and open a new session
New-O365ExchangeSession $365master
} while($Offset -lt $MbxMax)

Powershell Compare Objects from multiple sources

I'm trying to build out a script to compare multiple CSV files and identify the delta in one master file. I think I'm close to having what I need but, I'm running into an issue when trying to set the value for the property on the master object.
I'm pulling in one CSV file (Sample) that has Computer Name, Location, IP, Active Directory, SCCM that I'm comparing to outputs from Active Directory (Compare) with the same information. I just want to update the first file with either a yes or no that the system is in Active Directory in the column called AD.
Here is the code that I have and need some guidance on fixing it:
$Sample = Import-Csv C:\Scripts\Sample_test_v1.csv
$Compare = Import-Csv C:\Scripts\Sample_AD_v1.csv
$Final = #()
foreach ($Samples in $Sample)
{
$Final = New-Object System.Object
$Final | Add-Member -type NoteProperty -name "Computer Name" -value $Samples.ComputerName
$Final | Add-Member -type NoteProperty -name "IP Address" -value $Samples.IP
$Final | Add-Member -type NoteProperty -name "Location" -value $Samples.Location
If ($Samples.ComputerName -contains $compare)
{$Final | Add-Member -type NoteProperty -name "Active Directory" -value "Yes"}
Else
{$Final | Add-Member -type NoteProperty -name "Active Directory" -value "Yes"}
}
With contains, you want the collection to come first. (Also changes Samples/Sample for clarity)
$Samples = Import-Csv C:\Scripts\Sample_test_v1.csv
$Compare = Import-Csv C:\Scripts\Sample_AD_v1.csv
$NewSamples = foreach ($Sample in $Samples) {
If ($Compare.Computername -contains $Sample.ComputerName) {
$Sample.AD = "Yes"
} Else {
$Sample.AD = "No"
}
$Sample
}
$NewSamples | Export-Csv C:\Scripts\Sample_test_v1.new.csv -notype
I figured out my problem with the below code which works now:
$Final = #()
$Samples = Import-Csv C:\Scripts\Sample_test_v1.csv
$Compare = Import-Csv C:\Scripts\Sample_AD_v1.csv
foreach ($Sample in $Samples)
{
$Sys = New-Object System.Object
$Sys | Add-Member -type NoteProperty -name "Computer Name" -value $Sample.ComputerName
$Sys | Add-Member -type NoteProperty -name "IP Address" -value $Sample.IP
$Sys | Add-Member -type NoteProperty -name "Location" -value $Sample.Location
If ($compare.computername -contains $Sample.ComputerName )
{$Sys | Add-Member -type NoteProperty -name "Active Directory" -value "Yes"}
Else
{ $Sys | Add-Member -type NoteProperty -name "Active Directory" -value "No" }
$Final += $Sys
}

PowerShell export to csv. Only quote 1 set in each row

When I'm building a CSV Export it puts quotes around every set of parameters. However, I only want 1 set to have the quotes.
$UserInfo = New-Object System.Object
foreach ($user in $MailBoxList)
{
$UserInfo | Add-Member -Type NoteProperty -Name LegacyExchangeDN -Value $user.LegacyExchangeDN
$UserInfo | Add-Member -Type NoteProperty -Name CloudEmailAddress -Value $CloudEmailAddress
$UserInfo | Add-Member -Type NoteProperty -Name OnPremiseEmailAddress -Value $user.PrimarySMTPAddress.ToString()
$UserInfo | Add-Member -Type NoteProperty -Name MailboxGUID -Value $user.ExchangeGUID
$Users += $UserInfo
}
$Users | Export-CSV -Delimiter "," -Path ".\cloud.csv" -NoTypeInformation
This code results in this exported CSV:
"LegacyExchangeDN","CloudEmailAddress","OnPremiseEmailAddress","MailboxGUID"
"/o=MyUnit/ou=This Admin Group (BRBIDOMF87SRQLT)/cn=Recipients/cn=a0dd27c5djd864108cfa61dj37dj56c6-MyLastName, M","mMyLastName#WhereverImFrom.Bob.com","mMyLastName#AnotherDomain.com","687efe5e-4690-110e-86a5-69fr4cdecf7e"
What I'd like is just the first column of data to have double quotes and the rest without:
"/o=MyUnit/ou=This Admin Group (BRBIDOMF87SRQLT)/cn=Recipients/cn=a0dd27c5djd864108cfa61dj37dj56c6-MyLastName, M",mMyLastName#WhereverImFrom.Bob.com,mMyLastName#AnotherDomain.com,687efe5e-4690-110e-86a5-69fr4cdecf7e
Any thoughts?
You can "roll your own" csv file:
$Outfile = ".\cloud.csv"
'LegacyExchangeDN,CloudEmailAddress,OnPremiseEmailAddress' | Set-Content $Outfile
foreach($user in $MailBoxList)
{
$Data = #(
$user.LegacyExchangeDN,
$CloudEmailAddress,
$user.PrimarySMTPAddress.ToString()
)
'"{0}",{1},{2}' -f $Data | Add-Content $Outfile
}
Here's one solution. What it does is convert the objects to csv-strings and then modify them before saving the csv to a file.
foreach($user in $MailBoxList)
{
$UserInfo = New-Object System.Object
$UserInfo | Add-Member -Type NoteProperty -Name LegacyExchangeDN -Value $user.LegacyExchangeDN
$UserInfo | Add-Member -Type NoteProperty -Name CloudEmailAddress -Value $CloudEmailAddress
$UserInfo | Add-Member -Type NoteProperty -Name OnPremiseEmailAddress -Value
$user.PrimarySMTPAddress.ToString()
$UserInfo | Add-Member -Type NoteProperty -Name MailboxGUID -Value $user.ExchangeGUID
$Users += $UserInfo
}
#Convert to csv-formatted-strings
$csv = $Users | ConvertTo-Csv -NoTypeInformation -Delimiter ","
#Get header
$out = #($csv[0])
#Remove quotes for all but first column
$out += $csv[1..($csv.Length-1)] | % {
[regex]::Match($_,'(^"[^"]*",)(.*)') | % { "{0}{1}" -f $_.Groups[1], $_.Groups[2].Value.Replace('"',"") }
}
$out | Set-Content -Path ".\cloud.csv"
Another apporach without regex:
#Remove quotes for all but first column
$out += $csv[1..($csv.Length-1)] | % {
$values = $_ -split '","'
$values[0] + '"' + $values[1..($values.Length-1)] -join ','
}