0

I finally got the functionality of my script working now I want to save to CSV, Im using the | Export-CSV -path .\output.csv -Delimiter ";". but not able to get the data i need.

I'm creating a global empty array and trying to append items within in a foreach-object loop but get an empty CSV

im also runing my foraech-object as a job and piping the | Export-CSV -path .\output.csv -Delimiter ";" and get a random set of numbers

how can i get my data in to CSV?

My Script

Function Get-FileName{
    [System.Reflection.Assembly]::LoadWithPartialName(“System.windows.forms”) | Out-Null
    $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    $OpenFileDialog.initialDirectory = Get-Location
    $OpenFileDialog.filter = “All files (*.*)| *.*”
    $OpenFileDialog.ShowDialog() | Out-Null
    $OpenFileDialog.filename
}

$Importfile = Get-FileName
$Clients = Get-Content $Importfile

$Do = $Clients | ForEach-Object -Parallel {
    # CHECK IF  PC IS IN AD  AND  STATUS  OF  PC IN AD   ENABLED/DISABLED
    $O = get-ADComputer -Identity $_ -Properties Enabled
        if ($O."Enabled" -eq 'TRUE') {

            #CHECK IF PC IS  NETWORK ACCESSIBLE 
            if (Test-Connection -ComputerName $_ -Count 2 -Quiet){

                try{ 
                    #GET  LATEST KB PATCH INSTALLED 
                    Get-HotFix -ComputerName $_ -Description 'Security Update' | Select-Object -Last 1 # tried  to get csv from here  and only capture  what passes through here and not the  catch or elses also tryed appending this to empty array  
                    }
                catch{ 
                    "$_;An error occurred." 
                }  
            }
            else{
                "$_;not on line "
            }
        } 
        else{
            "$_;Disabled PC"
        } 
} -AsJob 

$Do | Receive-Job -Wait   # i tried  " | Export-CSV -path .\output.csv -Delimiter ";" " and  got random  data 
victorR
  • 129
  • 1
  • 13
  • the `Foreach-Object -Parallel` command is not available unless you are ps7+. you say that you are using ps3 ... so, are you getting any errors from that wrong usage? [*grin*] ///// also, using `$Job` for a variable name is somewhat misleading in that there are PSJob cmdlets. i _strongly_ recommend you NEVER use keywords or special purpose cmdlet nouns for variable names. – Lee_Dailey Dec 11 '20 at 02:31
  • Hey Lee_Dailey. I forgot to mentioned yesterday i upgraded to PS 7.01 and will change my variable names. I was not aware JOB was a key word ... just learning PS without formal study its more as hands on, on things because it needs to be done. thanks for the correction – victorR Dec 11 '20 at 02:45
  • `job` aint a keyword ... it is a fairly specific noun used in the `*-Job` cmdlets. using it for a $Var name can lead to confusion when folks read it and think ... "i don't see anything to do with jobs ...". [*grin*] ///// please REMOVE the ps3 tag and add the ps7 tag so that folks won't be confused by your tags. – Lee_Dailey Dec 11 '20 at 02:54
  • Done ! Thanks. You wouldn’t happen to know PS 7 ??? – victorR Dec 11 '20 at 02:58
  • thanks! unfortunately, i still haven't gone into ps7 at this time. i don't see anything obviously wrong with your code, tho. ///// i would likely switch to using `Invoke-Command` since you can give it a scriptblock and a list of target systems ... and it will run the scriptblock on each system in parallel. you can also catch the non-responders with `-ErrorVariable` or by comparing the responders to the target list. – Lee_Dailey Dec 11 '20 at 03:11
  • You need to stream a (list of) [`[pscustomobject]`](https://learn.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-pscustomobject?view=powershell-7.1) rather than a `[String]` which is required for the [`Export-Csv`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/export-csv?view=powershell-7.1) input. – iRon Dec 11 '20 at 08:11
  • @iRon I'm actually kinda new to PS and PS scripting and English is not my native lang. Do you have a link to a resource I can learn what you are talking about or can you explain in simpler terms please – victorR Dec 11 '20 at 09:10
  • @Lee_Dailey Unfortunately to run `Invoke-Command` requires WinRm to be enabled on client PC. Which is not and would have to enable service manually since network admin will not create a GPO ... with the current script im able to get the result i want but fail to create CSV the closets i have gotten is by doing this `Get-HotFix -ComputerName $_ -Description 'Security Update' | Select-Object -Last | Export-Csv -path .\OutputFile.csv -Delimiter ";"` but it only captures in the CSV the records that fall in that IF condition and not the errors or offlines .. – victorR Dec 11 '20 at 09:18
  • @Lee_Dailey As I mentioned, I tried creating a global empty array and tried to append data to array depending on what condition was met and on the end of the script tried pushing that to the CSV file, but array never populated info – victorR Dec 11 '20 at 09:23
  • @victorR - take a look at this >>> `Get-Help New-CimSessionOption -Parameter protocol` <<< and this >>> `Get-Help Invoke-Command -Parameter session` <<< //// that means you can use DCOM instead of WSMan. if you can use the WMI cmdlets to access those systems ... then you can use `Invoke-Command` via `New-CimSession`. [*grin*] – Lee_Dailey Dec 11 '20 at 09:25
  • @Lee_Dailey well it did connect to remote host however I'm not able to run 'invoke-command' . `cim-session` and `invoke-method` are a new monster i need to research ... can you provide an example of runing `invoke-command` though cimsession please – victorR Dec 11 '20 at 10:17
  • @victorR - use `New-CimSessionOption` to set the protocol. then use `New-CimSession` to create the sessions to all [or a group of] the targets. next, use the `-Session` parameter of `Invoke-Command` to tell it to use the collection of sessions as needed. last, feed the scriptblock to the `I-C` call. that otta do it. i don't currently have anything to test this on ... just my one home system. – Lee_Dailey Dec 11 '20 at 11:35
  • @Lee_Dailey I've tried that and thi is what i got `" Invoke-Command -session $ses {get-hotfix} Invoke-Command: Cannot bind parameter 'Session'. Cannot convert the "CimSession: PC-w032" value of type "Microsoft.Management.Infrastructure.CimSession" to type "System.Management.Automation.Runspaces.PSSession"`. this was after i created a new cimsession with DCOM protocol – victorR Dec 11 '20 at 16:20
  • @victorR - i see that iRon has posted a working Answer. since i don't have any way to test the CIMSession problems, i suggest letting that go and using the working solution iRon presented. – Lee_Dailey Dec 12 '20 at 01:41

1 Answers1

1

As "kinda new to PS" person, I recommend you to take a few steps back and simplify things along with removing the -Parallel switch which might obscure the output. As commented, the Export-Csv cmdlet requires a stream of only [pscustomobject] items, you can't combine this with strings (like "$_;An error occurred.") or an object with different properties.
See: Not all properties displayed and #13906 Add -UnifyProperties parameter to Select-Object

function UniteProperties { # https://github.com/PowerShell/PowerShell/issues/13906#issuecomment-717480544
  [System.Collections.Generic.List[string]] $propNames = @()
  [System.Collections.Generic.HashSet[string]] $hashSet = @()
  $inputCollected = @($input)
  $inputCollected.ForEach({ 
    foreach ($name in $_.psobject.Properties.Name) {
      if ($hashSet.Add($name)) { $propNames.Add($name) }
    }
  })
  $inputCollected | Select-Object $propNames
}

$Do = 2, 3, 0, 5 | ForEach-Object -Parallel {
    Try {
        [pscustomobject]@{ Name = "Client$_"; HotFix = 1/$_ } # some standard HotFix results
    }
    Catch {
        [pscustomobject]@{ message = "$_;An error occurred." }
    }
}
$Do | UniteProperties | ConvertTo-Csv # Or ... Export-Csv

"Name","HotFix","message"
"Client2","0.5",
"Client3","0.3333333333333333",
,,"Attempted to divide by zero.;An error occurred."
"Client5","0.2",
iRon
  • 20,463
  • 10
  • 53
  • 79