Advanced Windows PowerShell Scripting Video Training

Advanced Windows PowerShell Scripting Video Training
Advanced Windows PowerShell Scripting Video Training

Wednesday, November 28, 2012

Removing duplicate objects from an set of objects

The question that I took this evening involved a user who has some functional PowerShell code.  The needed a way to filter out any duplicate objects.  They were looking at using several loops.  In my college days, that would have been the answer.  As my favorite professor, Dan Matthews, put it, “Never Reinvent the Wheel”

PowerShell has built in functionality to remove duplicate items by using the Sort-Object cmdlet.  You need to use the –Property parameter to tell PowerShell which proper of the object you are looking for duplicates on and also you need to use the –Unique parameter to tell PowerShell to only leave unique objects (remove duplicates).

Below is some sample code to generate a set of 11 objects.  Two of those objects will have a duplicate value in Prop1.

# Create a dynamic array to hold the test objects.

$Array = @()

 

# Create 10 objects in the dynamic array.

For ($X = 0;$X -lt 10;$X++)

{

    $Obj = New-Object PSObject

    $Obj | Add-Member -MemberType NoteProperty -Name "Prop1" -Value $X

    $Obj | Add-Member -MemberType NoteProperty -Name "Prop2" -Value $True

    $Obj | Add-Member -MemberType NoteProperty -Name "Prop3" -Value $False

 

    # Add the object to the array

    $Array += $Obj

}

 

# Add a duplicate to the array.  The duplication will be on the property

# Prop1 with a value of 3

$Obj = New-Object PSObject

$Obj | Add-Member -MemberType NoteProperty -Name "Prop1" -Value 3

$Obj | Add-Member -MemberType NoteProperty -Name "Prop2" -Value $True

$Obj | Add-Member -MemberType NoteProperty -Name "Prop3" -Value $False

 

# Add the object to the array

$Array += $Obj

 

# View the contents of the array.  Notice the duplicate value in Prop 1

$Array | FT –autosize

 

# Divider between the two sets of data.

Write-host "-----------------------------------------------------------"

 

# Use the -Unique parameter of the Sort-Object cmdlet.

# Note the duplicate object is gone.

$Array | Sort-Object -Property Prop1 -Unique | FT -autosize

 

This output will display two sets of data.  One set will show all 11 objects (including the duplicate).  The second set was filtered using Select-Object in the last line of the code.

Prop1 Prop2 Prop3

----- ----- -----

    0  True False

    1  True False

    2  True False

    3  True False

    4  True False

    5  True False

    6  True False

    7  True False

    8  True False

    9  True False

    3  True False

 

 

-----------------------------------------------------------

 

Prop1 Prop2 Prop3

----- ----- -----

    0  True False

    1  True False

    2  True False

    3  True False

    4  True False

    5  True False

    6  True False

    7  True False

    8  True False

    9  True False

Notice in the second set that was filtered with Sort-Object, the duplicate value of 3 in Prop1 has been removed.

Monday, November 26, 2012

Executing a lot of code on multiple clients

I took a question today about how to execute a bunch of code on remote clients.  The users code worked for them on their local client, but they needed it to execute remotely.  This is a job for Invoke-Command!!!

Invoke command will let you take your existing code and run it on multiple clients.  Here is a basic example.

invoke-command -ScriptBlock {

   #<< Your code here >>

   } -ComputerName #<<Name of remote computer>>

 

Now for the part about executing this code against multiple clients.

 

$Servers = “SVR1”, “SVR2”, “SVR3”

ForEach ($Server in $Servers)

{

invoke-command -ScriptBlock {

   #<< Your code here >>

   } -ComputerName $Servers

}

 

In this example, we nest our invoke command  inside of a ForEach statement.  We provide a list of server names to $Servers and use this to cycle through each client.  You may want to add some error handling to this code.

Wednesday, November 21, 2012

Get the Name of a Server Returned with Data Using Get-Process

Here is a question that I had about using Get-Process.  The user needed the same basic information that Get-Process normally gives you, but they also needed the name of the computer that the data came from.  Their intent was to run this one command against multiple servers at the same time, but needed to separate the data by its source.

When you use the Get-WMIObject cmdlet, you get a few extra properties added in.  The on of interest in this case is __SERVER.  This will hold the name of the client that the data came from.  I could have just told the user to execute Get-WMIObject Win32_Process –ComputerName <List of names>.  But that would return a lot more data.  Also, I am on a very long flight back from Microsoft so I needed something to keep me from being bored.  Below is the result.

Since the user wanted to use this in a script or as a stand alone, I created a function that could be either dot sourced into memory or added as a http://mctexpert.blogspot.com/2011/04/creating-powershell-module.html as well as be added directly to a script.  It also includes a help file.

Function Get-Process2
{
[CmdletBinding(Helpuri
= 'http://get-help-jason-yoder.blogspot.com/2012/10/get-process2.html')]
Param (
    [Parameter(Mandatory
=$True)]$ComputerName,
    [
Switch]$Quiet,
    [
Switch]$FullDetail
)

   
# Cycle through each computer.
    ForEach ($Computer in $ComputerName)
    {
       
Try
        {
           
# Get the process information and include the client
            # that the information was received from.
           
           
If($FullDetail)
            {
              
$Data = Get-WmiObject Win32_Process
            }
           
Else
            {
               
$Data = Get-WmiObject Win32_Process `
                
-ComputerName $Computer `
                
-ErrorAction Stop |
                
Select-Object `
                
-Property Handles, NPM, PM, WS, VM, CPU, ID, Name, @{Label="ComputerName";Expression={$_.__Server}}
            }

           
Write-Output $Data
        }
# End: Try
        Catch
        {
           
# If the client could not be contacted, notify the user.
            If (!$Quiet)
            {
               
Write-Host "$Computer is not online" -ForegroundColor Red -BackgroundColor DarkRed
            }
        }
# End: Catch


    }
# End: ForEach ($Computer in $ComputerName)

<#
.SYNOPSIS
Returns process information on local and remote clients.

.DESCRIPTION
Returns process information on local and remote clients, but includes
the computer name.

.PARAMETER ComputerName
The name or names of the computers that you want to return process
information from.

.PARAMETER Quiet
Suppresses error messages.

.PARAMETER FullDetail
Returned the entire process object.  The default will return the
same information as Get-Process.

.EXAMPLE
Get-Process2  -ComputerName "Srv01", "Svr2", "Svr3"

Returns the same information as Get-Process, but also includes the
name of the source the data came from.

.EXAMPLE
Get-Process2  -ComputerName "Srv01", "Svr2", "Svr3" -Quiet

Returns the same information as Get-Process, but also includes the
name of the source the data came from. Any errors generated while
attmpting to contact the clients will be suppressed.

.EXAMPLE
Get-Process2  -ComputerName "Srv01", "Svr2", "Svr3" -FullDetail
Returns the entire Process object for each object on each server contacted.
This will return a very large amount of data.

.NOTES
-------------------------------------------------------------------------------
Provided as is with no warranty or support.
Jason Yoder, MCT  -  MCTExpert, Inc.
-------------------------------------------------------------------------------

#>
}
# -- End Function Get-Process2 ----------------------------------------------

Monday, November 19, 2012

Use the difference between event log time stamps to decide if you need to take action

Today I am on a long flight back to Indianapolis after a week of training at Microsoft. Being the geek that I am I decided to take a quick look at PowerShell.org to see if anybody in the community was having issues that I could help with before we took off. One community member needed to be able to tell if two events were being recorded more than 2 hours apart. If so, she wanted an action to take place.

I used the Subtract Method of the System.DateTime object that is given to you in the TimeCreated property of an individual event log to resolve this. In the below function, I have it extract the first two events that match the criteria in $EventHash. I then take the first returned event and subtract the second events time from the first and then look for the TotalHours property. If it is greater than the number of hours specified when the function was called, it returns True. If not, it returns False.  It also has a built in safety.  If 1 or less events are returned, the function defaults to False.

 
Function Get-EventTimeSpan
{
Param (
[Parameter(Mandatory
=$True)]$Hours
)
# Specify the criteria for your event here.
$EventHash = @{LogName = "System"; ID = 1014}

# Recover the first two events from the event log that matches
# the criteria in the $EventHash data.
$EventData = Get-WinEvent -FilterHashtable $EventHash -MaxEvents 2

# Verify that at least two events were recovered from the log.
# If there are less than 2 events recovered, Execute the ELSE
# Statement. The Else statement should execute code if only one
# or less events are found.
If ($EventData.Count -eq 2)
{
If ((($EventData[0].TimeCreated).Subtract(($EventData[1].TimeCreated)).TotalHours) -lt $Hours)
{
# Return $False if the time between events is less than the
# number of hours specified in $Hours.
Write-Output $False
}
Else
{
# Return $False if the time between events is greater than the
# number of hours specified in $Hours.
Write-Output $True
}
}
# End: If ($EventData.Count -lt 2)
Else
{
#If there are less than 2 events in the event log, return $False
Write-Output $False
}
# End: Else Statement for If ($EventData.Count -lt 2)



}
# ---- End Function Get-EventTimeSpan ---------------------------------------


9

Wednesday, November 14, 2012

Use PowerShell to Download HTML code from a website

Here is a little code to help you download the HTML code of a website to a file on your client.

Function Download-HTML
{
[CmdletBinding(HelpUri
="http://get-help-jason-yoder.blogspot.com/2012/10/download-html.html")]
Param(
[Parameter(Mandatory
=$True)]$Source = "www.MCTExpert.com",
[Parameter(Mandatory
=$True)]$SaveFile = "C:\Users\Jason\Documents\Temp\Download1.HTML",
[
Switch]$Quiet

)

#Create an object to hold the web content.
$DataObj = New-Object System.Net.WebClient


Try
{
# Use the System.Net.WebClient method: Download to attempt to
# download the data. If it dows not exists, then error out.
$DataObj.DownloadFile("Http://$source", $SaveFile)

# Once the file is found, notify the user if $Quite is $False.
If ($Quiet-eq $False)
{
Write-Host "Website text downloaded to $SaveFile" -foreground Green -background DarkGreen
}
}
Catch
{
# If the file is not available and the code errors, let the user
# know the file is not there unless $Quest is $True.
If ($Quiet-eq $False)
{
Write-Host "File not Available" -ForegroundColor Red -BackgroundColor DarkRed
}
}
<#
.SYNOPSIS
Saves HTML source code from the web to a file on your hard drive.

.DESCRIPTION
Allows you to specify a website and download the source code.

.PARAMETER Source
The website that you want to download the source code from.

.PARAMETER SaveFile
The destination path and file name that you want to save the source code to.

.PARAMETER Quiet
Suppresses on screen messages.

.EXAMPLE
Download-HTML -Source "www.MCTExpert.com" -SaveFile "C:\Data\Code.html"

Downloads the code from the web page www.MCTExpert.com and saves it to the
local hard drive in the Data folder as Code.html.

#>
}

Monday, November 12, 2012

Placing data into a CSV from multiple objects with PowerShell

I recently answered a question on PowerShell.org in which a user was sending data to a CSV file.  This data contain objects with multiple properties.  The problem with sending an object that contains objects to a CSV file with the Export-CSV is that a CSV file cannot store hieratical data.  This is what you get.  Take note of the data in the property “LogicalDisks”.

#TYPE System.Management.Automation.PSCustomObject
"Server_Name","MFG","LogicalDisks"
"LocalHost","JASON-PC","System.Object[]"

 

If you need to save and object that contains an object, send it to an XML file using Export-Clixml.  Here is the same data set as an XML file.

image

 

Notice the hierarchy is preserved.  When you use Import-Clixml, you can import this data into a variable and all the objects properties are restored.

 

In case this is not an option, below is the code that I sent to the individual who posted the question.  This is a combination of the code that they presented and my changes.  This code is an example of how to take an object that has multiple properties and add those properties to your output object in a way that prevents property name conflicts.

Function Get-Details
{
Param (
$ComputerName = "LocalHost"
)

ForEach ($Srv in $ComputerName)
{
$CompSys = Get-WmiObject Win32_ComputerSystem -computerName $Srv
$Proc = get-wmiobject Win32_Processor -ComputerName $Srv
$OS = Get-WmiObject Win32_OperatingSystem -computerName $Srv

$LDisk = Get-WmiObject win32_LogicalDisk -Filter "DriveType = 3" -ComputerName $Srv


# Create a blank object.
$Obj = New-Object -TypeName PSObject

# Add the objects properties.
$Obj | Add-Member -MemberType NoteProperty `
-Name
"Server_Name" `
-Value
$Srv

$Obj | Add-Member -MemberType NoteProperty `
-Name
"MFG" `
-Value
$CompSys.Name
# Continue to fill in your property data here

# The $Index will prevent the creation of Property names of the
# same type. Since the designed output is to a CSV, we need
# to not save an object inside of an object or the CSV will not
# have the designed data.

$Index = 0

# Create a property for each property of the logical disk that
# needs to be in the output. Take note of how the $Index value
# is used in the -Name parameter.
ForEach ($Disk in $LDisk)
{
$Obj | Add-Member -MemberType NoteProperty `
-Name
"DeviceID_$Index" `
-Value
$Disk.DeviceID

$Obj | Add-Member -MemberType NoteProperty `
-Name
"FreeSpace(GB)_$Index" `
-Value (
$Disk.FreeSpace/1GB).ToString("0.00")

$Index++
}



# Write the object to the pipeline.
Write-Output $Obj

}



}


Get-Details | Export-csv c:\users\jason\documents\temp\test1.csv

Wednesday, November 7, 2012

Backup event logs on multiple servers with PowerShell

This PowerShell cmdlet was developed for my PowerShell class in Miami.  This is very specific to their needs.  The requirement was to be able to backup event logs from multiple servers to a single location.  The logs needed to be saved in a folder structure of Year/Month.  They also needed an option to clear the log.  This was a fun one, but complex so I took it on.

It is designed as a function so you can add it to a custom library.

Function Backup-EventLog
{
[CmdletBinding(HelpUri = 'http://get-help-jason-yoder.blogspot.com/2012/10/backup-eventlog.html')]
Param(
    [Parameter(Mandatory=$True)][String[]]$ComputerName,
    [Parameter(Mandatory=$True)]$LogFiles,
    [Parameter(Mandatory=$True)][String]$Path,
    [Switch]$ClearLog,
    [Switch]$Quiet
)

    # Support Function: Write-Info --------------------------------------------
    # Provides pre-defined color formatting for text output.
    Function Write-Info
    {
    Param (
        $String,
        $Color,
        $Width = 80,
        $Quiet,
        [Switch]$NoWidth
    )

        If ($Quiet -eq $False)
        {
            # Get the width of the text.
            $StringWidth = $String.length

            If (($StringWidth -lt $Width) -and ($NoWidth -eq $False))
            {
                For ($X = $StringWidth;$X -le $Width; $X++)
                {
                    $String += " "
                }
            }

            Switch ($Color)
            {
            # Green Font
            "G1" {Write-Host $String -ForegroundColor Green `
                                     -BackgroundColor DarkGreen}
            "G2" {Write-Host $String -ForegroundColor DarkGreen `
                                     -BackgroundColor Green}
            "G3" {Write-Host $String -ForegroundColor Green `
                                     -BackgroundColor DarkBlue}
            "G4" {Write-Host $String -ForegroundColor Green `
                                     -BackgroundColor Black}
            "G5" {Write-Host $String -ForegroundColor Green}
       
            # Yellow Font
            "Y1" {Write-Host $String -ForegroundColor Yellow `
                                     -BackgroundColor DarkGray}
            "Y2" {Write-Host $String -ForegroundColor DarkGray `
                                     -BackgroundColor Yellow}
            "Y3" {Write-Host $String -ForegroundColor Yellow `
                                     -BackgroundColor DarkBlue}
            "Y4" {Write-Host $String -ForegroundColor Yellow `
                                     -BackgroundColor Black}
            "Y5" {Write-Host $String -ForegroundColor Yellow}
       
            # Red Font
            "R1" {Write-Host $String -ForegroundColor Red `
                                     -BackgroundColor DarkRed}
            "R2" {Write-Host $String -ForegroundColor DarkRed `
                                     -BackgroundColor Red}
            "R3" {Write-Host $String -ForegroundColor Red `
                                     -BackgroundColor DarkBlue}
            "R4" {Write-Host $String -ForegroundColor Red `
                                     -BackgroundColor Black}
            "R5" {Write-Host $String -ForegroundColor Red}       
       
            # Cyan Font
            "C1" {Write-Host $String -ForegroundColor Cyan `
                                     -BackgroundColor DarkCyan}
            "C2" {Write-Host $String -ForegroundColor DarkCyan `
                                     -BackgroundColor Cyan}
            "C3" {Write-Host $String -ForegroundColor Cyan `
                                     -BackgroundColor DarkBlue}
            "C4" {Write-Host $String -ForegroundColor Cyan `
                                     -BackgroundColor Black}
            "C5" {Write-Host $String -ForegroundColor Cyan}
       
            # White Font
            "W1" {Write-Host $String -ForegroundColor White `
                                     -BackgroundColor DarkGray}
            "W2" {Write-Host $String -ForegroundColor DarkGray `
                                     -BackgroundColor White}
            "W3" {Write-Host $String -ForegroundColor White `
                                     -BackgroundColor DarkBlue}
            "W4" {Write-Host $String -ForegroundColor White `
                                     -BackgroundColor Black}
            "W5" {Write-Host $String -ForegroundColor White}
       
            # Blue Font
            "B1" {Write-Host $String -ForegroundColor Blue 1 `
                                     -BackgroundColor DarkBlue}
            "B2" {Write-Host $String -ForegroundColor Gray `
                                     -BackgroundColor Blue}
            "B3" {Write-Host $String -ForegroundColor Blue `
                                     -BackgroundColor DarkBlue}
            "B4" {Write-Host $String -ForegroundColor Blue `
                                     -BackgroundColor Black}
            "B5" {Write-Host $String -ForegroundColor Blue}      
            }
        }
    }
    # End: Write-Info ---------------------------------------------------------

    # Support Function: Get-EventLogInfo --------------------------------------
    # Returns the event log file information from the target computer.
    Function Get-EventLogInfo
    {
    Param (
        $ComputerName
    )
       
        $Info = Get-WmiObject Win32_NTEventLogFile -ComputerName $ComputerName
        Write-Output $Info
    }

    # End: Get-EventLogInfo ---------------------------------------------------

    # Support Function: Create-FolderStructure --------------------------------
    # Creates the folder structure
    Function Create-FolderStructure
    {
    Param(
        $Path
    )
        [String]$DateString = $Path + "\" + ((Get-Date).Year).ToString() + `
            "\" + ((Get-Date).Month).ToString()

        If ((Test-Path $DateString) -ne $True)
        {
            Try
            {
                New-Item -Path $DateString -ItemType Directory -ErrorAction Stop
               
            }
            Catch
            {
                Write-Host "Cannot create folder." -ForegroundColor Red
                Write-Host  "You may not have neccessary permissions" `
                    -ForegroundColor Red
                Break
            }
        }
        Write-Output $DateString
      
    }
    # End: Create-FolderStructure ---------------------------------------------


    # If the user specified a credential, create a PSCredential object
    If ($Credential -ne $Null)
    {
        $CredObject = Get-Credential `
         -UserName $Credential `
         -Message "Provide the credentials of a user who can clear the Security Log"
   
        $CredObject | FL *
    }


    # Test to see if the account being used has admin rights.  Notify the user
    # if they do not.
    $isAdmin = (new-object System.Security.Principal.WindowsPrincipal([System.Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole("Administrators")
    If ($IsAdmin -eq $False)
    {
        Write-Info "Cmdlet not being executed as an Administrator." -Color Y1 -Quiet $Quiet
        Write-Info "You may not be able to backup all event logs." -Color Y1 -Quiet $Quiet
    }

    # Test to see if the backup location is online
    If (Test-Path -Path $Path)
    {
        Write-Info "Backup Storage is online" -Color G1 -Quiet $Quiet
        # Out-Null will supress unnessessary text.
        Create-FolderStructure $Path | Out-Null
    }
    Else
    {
        Write-Info "Backup storage is not online" -Color R1 -Quiet $Quiet
        Write-Info "Terminating Operation" -Color R1 -Quiet $Quiet
        Break
    }

    # Create the folder structure. Return the path to be
    # used for backing up the logs.
    $DateString = Create-FolderStructure -Path $Path

    # Create the date/time stamp to be added to the
    # names of the backed up logs. This format will be appended to the
    # end of the log file name as -Hour-Minute.evtx.
    [String]$NameString = "-" + ((Get-Date).Day).ToString() + `
        "-" + ((Get-Date).Hour).ToString() + `
        "-" + ((Get-Date).Minute).ToString() + ".evtx"

    # Create an array to hold the Objects from this cmdlet.
    # As the cmdlet cycles through each computer, it will add the objects
    # created to this array.  This array will be sent to the pipeline
    # once the ComputerName list has been depleted.
    $FinalObj = @()


   
    # Cycle through each computer and examine the logs.
    ForEach ($Computer in $ComputerName)
    {

   
        # Inform the user which computer is being anaylised.
        Write-Info "Connecting to $Computer." -Color W1 -Quiet $Quiet
       
        # Test for a connection to the computer.
        $ConnectionMade = $False
        $Connection = Test-Connection -ComputerName $Computer -Count 1 -Quiet

        If ($Connection)
        {
             $ConnectionMade = $True
        }
        Else
        {
            Write-Info "PING attempt to $Computer failed" -Color R2 -Quiet $Quiet
           
            # Create an object to hold the data for this computer.
            $Obj = New-Object -TypeName PSObject
       
            # Add the Server Name to the object.
            $Obj | Add-Member -MemberType NoteProperty `
                -Name "ComputerName" `
                -Value $Computer
           
            # Add the online property.
            $Obj | Add-Member -MemberType NoteProperty `
                -Name "Online" `
                -Value $False
       
            # Add object properties for each log and the data to be recorded
            # from each log.
            ForEach ($Log in $LogFiles)
            {
                # Create the property names.
                $Exists = $Log+"_Exists"
                $Backedup = $Log+"_BackedUp"
                $Cleared = $Log+"_Cleared"
                # Create the properties in the object
                $Obj | Add-Member -MemberType NoteProperty `
                    -Name $Exists `
                    -Value $False            

                $Obj | Add-Member -MemberType NoteProperty `
                    -Name $BackedUp `
                    -Value $False            

                $Obj | Add-Member -MemberType NoteProperty `
                    -Name $Cleared `
                    -Value $False   
               
                $FinalObj += $Obj            
       
            } # End: ForEach ($Log in $LogFiles)
        } # End: Else
       
        If ($ConnectionMade)
        {
            Write-Info "Connection Established" -Color G1  -Quiet $Quiet
          

            # Create an object to hold the data for this computer.
            $Obj = New-Object -TypeName PSObject
       
            # Add the Server Name to the object.
            $Obj | Add-Member -MemberType NoteProperty `
                -Name "ComputerName" `
                -Value $Computer

            # Add the online property.
            $Obj | Add-Member -MemberType NoteProperty `
                -Name "Online" `
                -Value $True
                       
            # Add object properties for each log and the data to be recorded
            # from each log.
            ForEach ($Log in $LogFiles)
            {
                # Create the property names.
                $Exists = $Log+"_Exists"
                $Backedup = $Log+"_BackedUp"
                $Cleared = $Log+"_Cleared"

                # Create the properties in the object
                $Obj | Add-Member -MemberType NoteProperty `
                    -Name $Exists `
                    -Value $False            

                $Obj | Add-Member -MemberType NoteProperty `
                    -Name $BackedUp `
                    -Value $False            

                $Obj | Add-Member -MemberType NoteProperty `
                    -Name $Cleared `
                    -Value $False            
       
            } # End: ForEach ($Log in $LogFiles)

            # Retrieve the event log data from the target client.      

            $EventLogData = Get-EventLogInfo -ComputerName $Computer


            # Determine if a log exists.
            ForEach ($Log in $LogFiles)
            {

                ForEach ($EventLog in $EventLogData)
                {
                    If ($EventLog.LogFileName -eq $Log)
                    {
                        $Exists = $Log+"_Exists"
                        $Obj.$Exists = $True          
                       
                        # Move the event log.
                        Try
                        {
                            Copy-Item -Path $EventLog.Name `
                             -Destination $DateString `
                             -ErrorAction Stop `
                             -ErrorVariable Test
                        }
                        Catch
                        {
                            If ($Error[0] -like "*Access to the path*is denied.*")
                                {
                                    Write-Info "You do not have sufficent rights to copy log file: $Log" `
                                     -Color R1 `
                                     -Quiet $Quiet
                                    Write-Info "Re-run this Backup-EventLog with elevated credentials" `
                                     -Color R1 `
                                     -Quiet $Quiet
                                }
                        }
                       
                        # Test to see if the copy was successful.
                        $TestPath = "$DateString\$Log.evtx"
                       
                       
                        If (Test-Path $TestPath)
                        {
                       
                            $Backedup = $Log+"_BackedUp"
                            $Obj.$BackedUp = $True

                            # Rename the file.
                            $NewName = $Computer + "-" + $Log+$NameString
                            Try
                            {
                               
                                Rename-Item -Path $TestPath `
                                 -NewName $NewName `
                                 -ErrorAction Stop
                                
                                
                            }
                            Catch
                            {
                                Write-Info "Rename not successful on $Log" -Color R1  -Quiet $Quiet
                                Write-Info "Action on your part may be neccessary" -Color R1  -Quiet $Quiet
                                Write-Info "This may be caused by executing this cmdlet" -Color R1  -Quiet $Quiet
                                Write-Info "more than once a minute." -Color R1  -Quiet $Quiet
                               
                                # Remove the Backup.
                                Remove-Item -Path $TestPath -Force
                               
                                # Reset the Backup flag to False.
                                $Obj.$BackedUp = $False
                               
                                $Success = $False
                            }

                            Write-Info "Completed attempt to backup $Log" "$ClearLog" -Color G3 -Quiet $Quite
                        } # End: If (Test-Path $TestPath)
                    
                      
                       # Clear the event log if necessary.
                       Write-Info "Clearing log: $Log" -Color C3 -Quiet $Quite


                       If (($ClearLog -eq $True) -and ($Obj.$Backedup -eq $True))
                       {
                       
                           Write-Info "Clearing log: $Log" -Color C3 -Quiet $Quite
                          
                           # use the WMI Method for
                           # Win32_NTEvenltLogFile.ClearEventLog()
                           # to clear the event long.  The Out-Null
                           # cmdlet suppresses information that would
                           # be displaced from the ClearEventLog() method.
                           $EventLog.ClearEventLog() | Out-Null
                                              

                           # Set the $Log_Cleared property to $True.
                           $Cleared = $Log+"_Cleared"
                           $Obj.$Cleared = $True

                       } # End: If ($ClearLog)



                    } # End: If ($EventLog.LogFileName -eq $Log)
                } # End: ForEach ($EventLog in $EventLogData)
            } # End: ForEach ($Log in $LogFiles)
        } # End: If ($ConnectionMade)       
        Else
        {
            Write-Info "$Computer is offline" -Color R1  -Quiet $Quiet
        } # End: Else (Test-Connection -ComputerName $Computer -Count 2)

        # Write the data to the FinalObj
        If ($Connection) {$FinalObj += $Obj}

        # Inform the user that the cmdlet has finished working on
        # a client.
        Write-Info "Completed backup attempt for $Computer" -Color G3  -Quiet $Quiet
    } # End: ForEach ($Computer in $ComputerName)

    # Send the data to the PowerShell pipeline.
    Write-Output $FinalObj | Select-Object -Unique -Property *

<#
.SYNOPSIS
Allows for the backing up and clearing of event logs.

.DESCRIPTION
Allows for the backing up and clearing of multiple event logs on multiple
Clients and Servers.  The event logs will be copied to the location
specified in the PATH parameter.  The cmdlet will automatically
create a file structure for Year and then month. 

The backed up files Names will have the format
Server-Log-Day-Hour-Minute to help denote separate backups
in the Month folders.

Logs are not cleared unless the CLEAR switch is invoked.

To work with the Security Log, the user must be running PowerShell
As an Administrator.


.PARAMETER ClearLog
Clears the log if the backup was successful.

.PARAMETER ComputerName
List of computer names in which to attempt a backup of event log data.

.PARAMETER LogFiles
List of all event logs to attempt to backup.

.PARAMETER Path
The root destination path to store the backup logs in.

.PARAMETER Quiet
Suppresses all information and warning messages.

.NOTES
===============================================================================
Copyright 2012 MCTExpert, Inc.

This script is provided without support, warranty, or guarantee.
User assumes all liability for cmdlet results.
===============================================================================

.EXAMPLE
 Backup-EventLog -ComputerName Indy-DC1 -LogFiles Security, Application -Path f:\Logs

 Backs up the Security and Application Logs from server Indy-DC1 to the path f:\Logs.

.EXAMPLE
Backup-EventLog -ComputerName Indy-DC1, Indy-CLI1, LON-SVR2 -LogFiles System -Path "\\LON-SVR1\Logs" -ClearLog| Where-Object {$_.online -eq $True}

ComputerName    : Indy-DC1
Online          : True
System_Exists   : True
System_BackedUp : True
System_Cleared  : True

ComputerName    : Indy-SVR2
Online          : True
System_Exists   : True
System_BackedUp : True
System_Cleared  : True

Returns all clients eventlog backup information for clients that were online and connected.

.EXAMPLE
PS F:\code> Backup-EventLog -ComputerName Indy-DC1, Indy-CLI1, Indy-SVR2 -LogFiles System -Path "\\Indy-SVR1\Logs" -ClearLog | FT


ComputerName Online System_Exists System_BackedUp System_Cleared
------------ ------ ------------- --------------- --------------
Indy-DC1     True   True          True             True
Indy-CLI1    False  False         False            False
Indy-SVR2    True   True          True             True


.EXAMPLE
Backup-EventLog -ComputerName Indy-DC1, Indy-CLI1, Indy-SVR2 -LogFiles System, application, Security -Path "\\Indy-SVR1\Logs" -ClearLog -Quiet

ComputerName         : Indy-DC1
Online               : True
System_Exists        : True
System_BackedUp      : True
System_Cleared       : True
application_Exists   : True
application_BackedUp : True
application_Cleared  : True
Security_Exists      : True
Security_BackedUp    : True
Security_Cleared     : True

ComputerName         : Indy-CLI1
Online               : False
System_Exists        : False
System_BackedUp      : False
System_Cleared       : False
application_Exists   : False
application_BackedUp : False
application_Cleared  : False
Security_Exists      : False
Security_BackedUp    : False
Security_Cleared     : False

ComputerName         : Indy-SVR2
Online               : True
System_Exists        : True
System_BackedUp      : True
System_Cleared       : True
application_Exists   : True
application_BackedUp : True
application_Cleared  : True
Security_Exists      : True
Security_BackedUp    : True
Security_Cleared     : True

Backups and clears all System, Application, and Security events on server
Indy-DC, Indy-CLI1, and Indy, SVR2.  The logs are backup on Indy-SVR2. 
All status messages are suppressed.


#>

}