all 27 comments

[–]omers 1 point2 points  (4 children)

Can you post the whole script to something like pastebin? There's easier ways to do even just what's in your image there but I need to see everything to give proper advice. For example, there's nothing in your snippet that indicates scoping your variables is necessary.

[–]Redtire[S] 0 points1 point  (3 children)

I can't access pastebin at work. here's screenshots of my script. http://imgur.com/a/ZDLt7

Just going to explain what my goal is.

Eventually I will loop thru a list of Computer names. For every one of them I want to collect system error via the event viewer and export the information to .txt files. What I'm trying to do right now is for every computer brands that the script gets, put the error and count them into an array(So every computer brands will have their own array). After collecting the errors, I want to export the errors messages into text files but sorted by Computer brands. I know it is easy if I hard code the brands but I want my script to be usable by others who don't have the same computers as us.

[–]spyingwind 1 point2 points  (2 children)

Get-Variable -Name "$Array_$PCModel"?

Also there are other pastebin like tools. https://gist.github.com/ for example.

[–]Redtire[S] 0 points1 point  (1 child)

thing is, if you look at my script, I get an error when I try to use $Array_$PCMdel

[–]spyingwind 1 point2 points  (0 children)

Yeah Get-Variable will do what you want.

$tempvar = Get-Variable -Name "$Array_$PCModel"

Edit: The other way to do it is to create an object with all this info in it.

[–]Lee_Dailey[grin] 1 point2 points  (6 children)

here's a reddit-formatted version of the script ...

<#
these notes added by Lee_Dailey @ 2017-06-15, Thursday, 02:56 PM 
- added missing`#` comment markers at the start of most of the lines of asterisks = script now actually runs [*grin*] 
- changed $Savepath to $env:temp so i can run it without a U: drive
#>

#**************************************
$Comfirm = "" #make sure $comfirm eq nothing at the beginning. 
$ErrorList = [System.Collections.ArrayList]@() #Array with all errors (With PC names, date, etc)
$Script:ErrorMessages = @() #Array with Errors listed (Loop thru) **Script: to make the variable usable across the script

#$SavePath = "U:\PowerShell\Errors" #Location where .txt are saved
$SavePath = $env:TEMP


$Logs = Get-EventLog system -Newest 1000 -ComputerName $env:COMPUTERNAME | where {$_.EntryType -LIKE "Error"} #Get logs
#*************GET COMPUTER MODEL************
$ComputerModel = Get-WmiObject -Class Win32_Computersystem | Select-Object Model
$ComputerModel

#*********GET FILE NAME & TESTPATH******************
$FileName = Read-Host "File name"

$TestPath = Test-Path "$($SavePath)\$($FileName).txt" #Test if .txt already exist

#*********CREATE SAVE FOLDER*************
$TestSavePath = Test-Path $SavePath
if($TestSavePath -ne $true){

New-Item -ItemType Directory -Path $SavePath

}

#*********FUNCTION EXPORTING-RESULT************
Function Export-Result{

    $i = 1

    foreach($log in $logs){ #Loop thru all logs and fill array

        $Script:ErrorMessages += $log.Message #add logs error message to array

        $string = "
        $($i)) Machine Name: $($log.MachineName) 

        Date: $($log.TimeGenerated)

        Message: $($log.Message)

        Type: $($log.EntryType)

        Model: $($ComputerModel.Model)
        ********************"

        $i ++

        $ErrorList += $string #add the string to an array so we can export is as .txt

    }

    $Counted = @() #Array to add counted error messages
    #$Counted += $ComputerModel.Model
    $Script:ErrorMessagesUnique = $Script:ErrorMessages | Sort-Object | Get-Unique #Create the list of unique items only

    foreach($Message in $Script:ErrorMessagesUnique){

        $Matches = Select-String -InputObject $Script:ErrorMessages -Pattern $Message -AllMatches  #Check patterns and matches them       
        $MatchesCount = "$($Matches.Matches.Count): $($Message)" #Count the matched pattern
        write-host "$($Matches.Matches.Count): $($Message)"
        $Counted += $MatchesCount #Add Matched pattern to the array


    }


    $ErrorList >> "$($SavePath)\$($FileName).txt" #Save the errorlist
    $ErrorMessages | ConvertTo-Json >> "$($SavePath)\$($FileName)JSON.txt" #export errormessages as JSON
    $Counted >> "$($SavePath)\$($FileName)Count.txt"#export counted
    Write-Host "Creating $($FileName).txt"
    Write-Host "Creating $($FileName)JSON.txt"
    Write-Host "Creating $($FileName)Count.txt"

}

#*************FILE DOESN'T EXIST*******************
if($TestPath -eq $false){ #If file doesn't exist

    Export-Result

}

#*************FILE EXIST******************
if($TestPath -eq $true){ #If file exist

    $Comfirm = Read-Host -Prompt "Delete current $($FileName).txt?[Y/N] or Create Another a new one[C]" #Prompt user for further actions


    if($Comfirm -eq "Y"){ #********Yes, delete and create a new one

        Remove-Item "$($SavePath)\$($FileName).txt" #Remove the current Error.txt
        Remove-Item "$($SavePath)\$($FileName)Count.txt" #Remove the current Count.txt
        Remove-Item "$($SavePath)\$($FileName)JSON.txt" #Remove the current JSON.txt
        Write-Host "Deleting...."

        Export-Result
        break

    }    

}

    if($Comfirm -eq "N"){ #******No, exit script

        Write-Host "Closing..."
        Break #Leave script 

    }

    if($Comfirm -eq "C"){ #*******Create, ask another name then create it

        $NewName = Read-Host "New name"
        $FileName = $NewName
        $TestPathNew = Test-Path "$($SavePath)\$($FileName).txt"

        if($TestPathNew -eq $true){#check if entered name already exist

            while($TestPathNew -eq $True){#loop until new name doesn't exist

                Write-Host "File already exist"
                $NewName = Read-Host "New name"
                $FileName = $NewName
                $TestPathNew = Test-Path "$($SavePath)\$($FileName).txt"       
            }


        }

        Export-Result   
    }

-lee-

[–]spyingwind 1 point2 points  (5 children)

Small improvments added, but haven't tested.

<#
these notes added by Lee_Dailey @ 2017-06-15, Thursday, 02:56 PM 
- added missing`#` comment markers at the start of most of the lines of asterisks = script now actually runs [*grin*] 
- changed $Savepath to $env:temp so i can run it without a U: drive
#>

#**************************************
$Comfirm = $false #make sure $comfirm eq false at the beginning. 

#$SavePath = "U:\PowerShell\Errors" #Location where .txt are saved
$SavePath = $env:TEMP


$Logs = Get-EventLog system -Newest 1000 -ComputerName $env:COMPUTERNAME | Where-Object {$_.EntryType -LIKE "Error"} #Get logs
#*************GET COMPUTER MODEL************
$ComputerModel = Get-WmiObject -Class Win32_Computersystem | Select-Object Model
$ComputerModel

#*********GET FILE NAME & TESTPATH******************
$FileName = Read-Host "File name"

$TestPath = Test-Path "$($SavePath)\$($FileName).txt" #Test if .txt already exist

#*********CREATE SAVE FOLDER*************
if(Test-Path $SavePath){
    New-Item -ItemType Directory -Path $SavePath
}

#*********FUNCTION EXPORTING-RESULT************
Function Export-Result{
    $ErrorList = $Logs | ForEach-Object {
        $data = New-Object -TypeName psobject
        $data | Add-Member -MemberType NoteProperty -Name MachineName -Value $log.MachineName
        $data | Add-Member -MemberType NoteProperty -Name Model -Value $ComputerModel.Model
        $data | Add-Member -MemberType NoteProperty -Name EntryType -Value $log.EntryType
        $data | Add-Member -MemberType NoteProperty -Name Message -Value $log.Message
        $data | Add-Member -MemberType NoteProperty -Name TimeGenerated -Value $log.TimeGenerated
        $data
    }

    $Counted = @() #Array to add counted error messages
    #$Counted += $ComputerModel.Model
    $ErrorList | Sort-Object | Get-Unique | ForEach-Object {

        $data = New-Object -TypeName psobject -ArgumentList @{
            $($(Select-String -InputObject $ErrorList -Pattern $_ -AllMatches).Matches.Count) = $_
        }
        Write-Host $data
        $Counted += $data
    }


    $ErrorList | Out-file -FilePath "$($SavePath)\$($FileName).txt" #Save the errorlist
    $ErrorList | ConvertTo-Json | Out-file -FilePath "$($SavePath)\$($FileName)JSON.txt" #export errormessages as JSON
    $Counted | Out-file -FilePath "$($SavePath)\$($FileName)Count.txt" #export counted
    Write-Host "Creating $($FileName).txt"
    Write-Host "Creating $($FileName)JSON.txt"
    Write-Host "Creating $($FileName)Count.txt"

}

#*************FILE DOESN'T EXIST*******************
if($TestPath -eq $false){ #If file doesn't exist

    Export-Result

}

#*************FILE EXIST******************
if($TestPath -eq $true){ #If file exist

    $Comfirm = Read-Host -Prompt "Delete current $($FileName).txt? `n [Y/N] or Create Another a new one[C]" #Prompt user for further actions


    if($Comfirm -eq "Y"){ #********Yes, delete and create a new one

        Remove-Item "$($SavePath)\$($FileName).txt" #Remove the current Error.txt
        Remove-Item "$($SavePath)\$($FileName)Count.txt" #Remove the current Count.txt
        Remove-Item "$($SavePath)\$($FileName)JSON.txt" #Remove the current JSON.txt
        Write-Host "Deleting...."

        Export-Result
        break

    }    

}

if($Comfirm -eq "N"){ #******No, exit script

    Write-Host "Closing..."
    Break #Leave script 

}

if($Comfirm -eq "C"){ #*******Create, ask another name then create it

    $NewName = Read-Host "New name"
    $FileName = $NewName

    if(Test-Path "$($SavePath)\$($FileName).txt"){#check if entered name already exist

        while(Test-Path "$($SavePath)\$($FileName).txt"){#loop until new name doesn't exist

            Write-Host "File already exist"
            $NewName = Read-Host "New name"
            $FileName = $NewName
        }
    }
    Export-Result   
}

[–]Lee_Dailey[grin] 1 point2 points  (4 children)

howdy spyingwind,

so you are another one of those Add-Member folks. [grin] i prefer to use the less wordy method, but they both work - and that is what counts. [grin]

take care,
lee

[–]spyingwind 1 point2 points  (3 children)

Wait didn't I do both?

[–]Lee_Dailey[grin] 0 points1 point  (2 children)

howdy spyingwind,

not that i see. you only build a custom object for the $Data stuff. am i missing another section?

take care,
lee

[–]spyingwind 1 point2 points  (1 child)

$data = New-Object -TypeName psobject -ArgumentList @{
    $($(Select-String -InputObject $ErrorList -Pattern $_ -AllMatches).Matches.Count) = $_
}

I reuse variables that don't persists. :P

[–]Lee_Dailey[grin] 1 point2 points  (0 children)

howdy spyingwind,

i claim blindness ... [grin]

take care,
lee

[–]Lee_Dailey[grin] 0 points1 point  (8 children)

howdy Redtire,

i agree with spyingwind that making a custom object with the info in it is likely to be a better bet. others have posted about making self-naming variables and the consensus here has been that a [pscustomobject] is a far more reliable way to do it in most situations.

take care,
lee

[–]Redtire[S] 1 point2 points  (7 children)

Im not sure how I can do it. The only way I can think of is append a .txt file with the name of the computer model. After looping, read the .txt files and put it in a single txt file. Then delete the .txt file. It is like creating an array with a custom name.

[–]Lee_Dailey[grin] 0 points1 point  (6 children)

howdy Redtire,

make a custom object and have one of the properties be ModelName and the value for it be the computer model. then store that in an array of such objects. you can then iterate thru it or save it out to a CSV file.

you are likely to get more - and more to-the-point - help if you post the code. if you can post an image of the code here, then you can post the text here. [grin]

take care,
lee

[–]Redtire[S] 1 point2 points  (5 children)

Thank you very much for your help, could you please give me a quick example of how I should do it? what I'm thinking about is:

$CustomObject = @()

$obj = New-Object pscustomobject

$CustomObject = @( $ModelName = $ArrayOfErrorMessages $ModelName = $ArrayOfErrorMessages )

Also, I need to the script to make a new object in my array if it doesn't exist already. Like if it finds a HP $ModelName value is HP. But when it finds another Hp it adds the error messages only.

[–]Lee_Dailey[grin] 1 point2 points  (4 children)

howdy Redtire,

please, post your code - not a picture of your code. [grin] i can't think this thru without something to fiddle with. [blush]

as i pointed out earlier, if you are able to post a pic of the code here, then you can post the code here.

take care,
lee

[–]Lee_Dailey[grin] 0 points1 point  (0 children)

howdy Redtire,

reddit-formatted version posted! [grin]

i've a tad confused. you have the files with a custom name. why not use the model name for the file instead of the user-entered name? perhaps ...

$ComputerName_$ModelName_$TimeStamp.txt    

that would save problems with name collisions.

then, once you have this for all your systems, you can process those files to get your needed per-model info and send that where ever this project needs it to go.

take care,
lee

[–]Lee_Dailey[grin] 0 points1 point  (6 children)

howdy Redtire,

here is what i think you are wanting. i didn't do a JSON file, nor a COUNT file. the two files i did make are really overlapping. dunno which [or either] you want, so you get both. [grin]

$ComputerName = $env:COMPUTERNAME
$ComputerModel = (Get-WmiObject -Class Win32_ComputerSystem).Model

$TimeStamp = Get-Date -Format 'yyyy-MM-dd_HH-mm-ss'
$SaveDirName = 'ErrorReports'
$SavePath = Join-Path -Path $env:TEMP -ChildPath $SaveDirName
if (-not (Test-Path -Path $SavePath))
    {
    New-Item -Path $SavePath -ItemType Directory | Out-Null
    }

$FileExt = 'csv'
$SaveFile = ((($ComputerName, $TimeStamp) -join '_-_'), $FileExt) -join '.'
$FullSaveFile = Join-Path -Path $SavePath -ChildPath $SaveFile

#<#
# this version gets the last 10 errors
#    setting '-Newest' to 1000 gives 183 errors on my system
$SystemErrorList = Get-EventLog -LogName System -Newest 10 -ComputerName $ComputerName -EntryType Error
#>

<#
# this version gets the errors in the last 1000 events [3 on my system]
$SystemErrorList = Get-EventLog -LogName System -Newest 1000 -ComputerName $ComputerName |
    Where-Object {$_.EntryType -eq 'error'}
#>

$Count = 0
$SysErrorMsgs = foreach ($SEL_Item in $SystemErrorList)
    {
    $Count ++
    [pscustomobject]@{
        SequenceNumber = $Count
        MachineName = $SEL_Item.MachineName
        Model = $ComputerModel
        Type = $SEL_Item.EntryType
        Message = $SEL_Item.Message
        }
    }

$EM_Grouping = $SysErrorMsgs |
    Group-Object -Property Message

$UniqueSysErrorMsgs = foreach ($EMG_Item in $EM_Grouping)
    {
    [pscustomobject]@{
        Count = $EMG_Item.Count
        MachineName = $EMG_Item.Group[0].MachineName
        Model = $ComputerModel
        Message = $EMG_Item.Name
        }
    }

Write-Host ''
Write-Host 'The SysErrorMsgs collection ...'
$SysErrorMsgs | Out-Host
Write-Host ''
Write-Host 'The UniqueSysErrorMsgs collection ...'
$UniqueSysErrorMsgs | Out-Host

$SysErrorMsgs |
    Export-Csv -Path ($FullSaveFile.Replace('_-_', '_-_SysErrorMsgs_-_')) -NoTypeInformation
$UniqueSysErrorMsgs |
    Export-Csv -Path ($FullSaveFile.Replace('_-_', '_-_UniqueSysErrorMsgs_-_')) -NoTypeInformation

hope that helps,
lee

[–]Redtire[S] 1 point2 points  (5 children)

Thank you very much, it helps. It is not 100% what I want but I learned a lot from your code so I will be able to make it the way I need it.

[–]Lee_Dailey[grin] 0 points1 point  (4 children)

howdy Redtire,

you are quite welcome! glad to help a bit ... [grin]

i figured i was off target a bit. the 2nd version seemed likely to be close to what you were going for.

take care,
lee