Posts RSS Comments RSS 130 Posts and 202 Comments till now

Blog Archives

Consortio Services Podcast

I had the chance to spend some time with the Consortia folks last night discussing Powershell and its place for the administrator in the next couple of years. Please stop by and listen to the Podcast.

http://www.cstechcast.com/home.aspx?Episode=8

More Info:
Consortio Services was founded by 3 technology experts who have over 35 years of combined expertise in nearly all facets of Information Technology. They have gained real world knowledge in such diverse areas as Networking Systems infrastructure, Telephony support, Operating System maintenance, Database Architecture, Design, and Administration, and Software design and support.

Eric Beehler - Network Technologies Consultant
Eric Johnson - Database Technologies Consultant
Joshua Jones - Operating Systems Consultant

Visit the website here
http://www.consortioservices.com/index.shtml

Format-XML (Journey to Pretty XML output)

I ran across a need to use Export-CliXML to produce human readable XML. Since, I never really cared what the output looked like so I let the blob go.

Now I care :)
I sent a message to the Powershell Dev Team and as always they are super speedy in response. (less than 1hr… that is INSANE.)

Enter Format-XML
http://blogs.msdn.com/powershell/archive/2008/01/18/format-xml.aspx

Help for Export-Clixml
http://technet.microsoft.com/en-us/library/bb978636.aspx

Thanks Again Jeffrey and Team!

p.s. I dont believe I ever said the output (Export-CliXML) looked like crap… just not Pretty :)

New Powershell Podcast is out and I am a guest!!!

The new PodCast is out and avaible here http://powerscripting.wordpress.com/2007/11/09/powerscripting-podcast-episode-12

I was happy and proud to be the first guest. Thanks GUYs!

Using Switch -RegEx to create Custom Object (Getting HBA Info)

The other day I had a need to collect HBA (Host Base Fiber Adapters) from all my Servers. So the first place I looked was at WMI, but unfortunately… no dice. It didnt have the information I needed. The only way I knew to get the info I needed was to use was HBACmd.exe (utility to collect HBA information remotely.) So I went to writing a wrapper script in powershell to call the exe and then grep the text for what I was looking for, but I thought… HEY! Thats not the powershell thing to do! We do objects not text. So I went to parsing the text and making an object out of it. The script below is the result and while I dont believe many of you will find it particularly useful as it has a VERY specific use, I wanted to share with you how I went about objectizing the output.

Here is a littel Q and A on the script

Q: Purpose?
A: To get all the HBA information include Type, Firmware, Bios, Target Lun, WWN and a slew of other stuff.

Q: Why Did I objectize my text?
A: Because I know can simply use properties to filter and output data. Like what Machines have what Bios and what type of HBAs they have. Before I would have the parse the text for every different senario… now I just use where-object and filter away.

I few things that I wanted to point out here are the use of Switch to create the Custom Objects. IMO, Switch is one of the most powerful commands in the Powershell Language. It is INSANELY Powerfull. To be honest, It is pretty much the only one you need.

To compare it “Select Case” in vbscript would be insulting, but it can peform a similar function Like

switch ($a){
     Value1    {"It was Value 1"}
     Value2    {"It was Value 2"}
     Value3    {"It was Value 3"}
     Value4    {"It was Value 4"}
}

It would take a whole series of post to completely cover switch, but for this one I only want to go over -regex use. For complete use read the help located:
PS> Get-help About_Switch # Read it, Learn it, Love it

Some Quick Notes about Switch
- Can use RegEx, WildCard, Exact, CaseSensitive, or File options.
- It takes input via Pipeline {expression} or File. The cool thing is the pipeline can be any expression that results in piped output.
- For each match it can perform any ScritpBlock use $_ as the current Item
- It performs EVERY match on each element unless you use Continue after a match to stop processing that record

Like I said, Switch is insanely powerful. Just one of those powers is using RegEx for comparison.

Here is an example of using the -RegEx option

switch -RegEx (Get-ChildItem C:\test)
{
    "^\d"                  {"Starts with number:          " + $_.FullName}
    "\d"                   {"Has a number in it:          " + $_.FullName}
    "[^A-Za-z]"            {"Does NOT start with Number:  " + $_.FullName}
    "tmp"                  {"Has ‘tmp’ in it:             " + $_.FullName}
    # Notice that you can even use and expression to match
    {$_.Mode -match "-a"}  {"Has Archive Bit Set:         " + $_.FullName}
}

Now.. lets look at the script below. You will noticed I used RegEx to decide what value gets put in to what property of the object.

The script converts the output of three commands into two different objects. Lets look at one of them

It takes text like This

Manageable HBA List

Port WWN   : 10:00:00:00:11:11:11:11
Node WWN   : 20:00:00:00:11:11:11:11
Fabric Name: 00:00:00:00:00:00:00:00
Flags      : 0000f0a5
Host Name  : Server1
Mfg        : Emulex Corporation

Port WWN   : 10:00:00:00:22:22:22:22
Node WWN   : 20:00:00:00:22:22:22:22
Fabric Name: 00:00:00:00:00:00:00:00
Flags      : 0000f0a5
Host Name  : Server1
Mfg        : Emulex Corporation

And converts Into an object like This

  TypeName: System.Management.Automation.PSCustomObject

Name        MemberType   Definition
—-        ———-   ———-
Equals      Method       System.Boolean Equals(Object obj)
GetHashCode Method       System.Int32 GetHashCode()
GetType     Method       System.Type GetType()
ToString    Method       System.String ToString()
Fabric      NoteProperty System.String Fabric=00:00:00:00:00:00:00:00
Flags       NoteProperty System.String Flags=0000f0a5
HBADetail   NoteProperty System.Object[] HBADetail=System.Object[]
Host        NoteProperty System.String Host=Server1
LUN         NoteProperty System.String LUN=01
MFG         NoteProperty System.String MFG=Emulex Corporation
NodeWWN     NoteProperty System.String NodeWWN=20:00:00:00:11:11:11:11
PortWWN     NoteProperty System.String PortWWN=10:00:00:00:11:11:11:11

Here is the Script

Param($List,$HostName,[switch]$FullDetail,[switch]$Verbose)
Begin{
    $erroractionpreference = "SilentlyContinue"
    $HBACMDPath = "<path To HbaCmd.exe>"
    function CreateHBAListObj{
        Param($srv)
        $objCol = @()
        $result = &"$HBACMDPath" "h=$srv" ListHBAs
        foreach($item in $result)
        {
            $parsd = $item.split([string[]](": "),[system.StringSplitOptions]::RemoveEmptyEntries)
            switch -regex ($parsd[0])
            {
                "^Port" {
                            $myobj = "" | Select-Object Host,PortWWN,NodeWWN,Fabric,Flags,LUN,MFG
                            $myobj.PortWWN = $parsd[1]
                            $myobj.Lun = GetTargetLun $srv $myobj.PortWWN
                        }
                "^Node" {$myobj.NodeWWN = $parsd[1]}
                "^Fabr" {$myobj.Fabric  = $parsd[1]}
                "^Flag" {$myobj.Flags   = $parsd[1]}
                "^Host" {$myobj.Host    = $parsd[1]}
                "^MFG " {
                            $myobj.MFG     = $parsd[1]
                            $objCol += $myObj
                        }
            }
        }
        $objCol
    }
    function CreateHBAInfoObj{
        Param($srv,$wwn)
        $objCol = @()
        $result = &"$HBACMDPath" "h=$srv" HBAAttrib $wwn

        $myobj = "" |Select-Object Host,MFG,SN,Model,ModelDesc,NodeWWN,NodeSymname,
                                   HWVersion,ROM,FW,VenderID,Ports,DriverName,DeviceID,HBAType,
                                   OpFW,SLT1FW,SLT2FW,IEEEAddress,BootBios,DriverVer,KernelVer
        foreach($item in $result)
        {
            $parsd = $item.split([string[]](": "),[system.StringSplitOptions]::RemoveEmptyEntries)
            switch -regex ($parsd[0])
            {
                "^Host"         {$myobj.Host         = $parsd[1]}
                "^Manufacturer" {$myobj.MFG          = $parsd[1]}
                "^Serial"       {$myobj.Sn           = $parsd[1]}
                "^Model  "      {$myobj.Model        = $parsd[1]}
                "^Model Desc"   {$myobj.ModelDesc    = $parsd[1]}
                "^Node WWN "    {$myobj.NodeWWN      = $parsd[1]}
                "^Node Symname" {$myobj.NodeSymname  = $parsd[1]}
                "^HW"           {$myobj.HWVersion    = $parsd[1]}
                "^Opt"          {$myobj.ROM          = $parsd[1]}
                "^FW"           {$myobj.FW           = $parsd[1]}
                "^Vender"       {$myobj.VenderID     = $parsd[1]}
                "^Number"       {$myobj.Ports        = $parsd[1]}
                "^Driver Name"  {$myobj.DriverName   = $parsd[1]}
                "^Device"       {$myobj.DeviceID     = $parsd[1]}
                "^HBA Type"     {$myobj.HBAType      = $parsd[1]}
                "^Operational"  {$myobj.OpFW         = $parsd[1]}
                "^SLI1 FW"      {$myobj.SLT1FW       = $parsd[1]}
                "^SLI2 FW"      {$myobj.SLT2FW       = $parsd[1]}
                "^IEEE"         {$myobj.IEEEAddress  = $parsd[1]}
                "^Boot "        {$myobj.BootBios     = $parsd[1]}
                "^Driver Ver"   {$myobj.DriverVer    = $parsd[1]}
                "^Kernel "      {$myobj.KernelVer    = $parsd[1]
                                 $objCol += $myObj}
            }
        }
        $objCol
    }
    function GetTargetLun{
        Param($srv,$wwn)
        $objCol = @()
        $result = &"$HBACMDPath" "h=$srv" TargetMapping $wwn
        [int]$lun = 0
        switch -regex ($result)
        {
            "^SCSI OS Lun" {$lun = $_.split([string[]](": "),[system.StringSplitOptions]::RemoveEmptyEntries)[1].trim()}
        }
        "{0:x}" -f $lun
    }
    function Ping-Server {
        Param([string]$srv)
        if($srv -eq ""){return $false}
        $pingresult = Get-WmiObject win32_pingstatus -f "address=’$srv’"
        if($pingresult.statuscode -eq 0) {$true} else {$false}
    }
    Write-Host
    if($verbose){$VerbosePreference = "Continue"}
}
Process{
    if($_)
    {
        Write-Host "Getting HBA Info from $_"
        if($FullDetail)
        {
            $MyObject = CreateHBAListObj $_
            $HBADetail = $MyObject | %{CreateHBAInfoObj $_.Host $_.PortWWN}
            $MyObject | add-Member -Name HBADetail -type NoteProperty -Value $HBADetail -force
            $MyObject
        }
        else
        {
            $MyObject = CreateHBAListObj $_
            $MyObject
        }
    }
}
End{
    if($list)
    {
        $servers = Get-Content $list
        Write-Host "Running HBA Check against Servers in $list"
        foreach($server in $servers)
        {
            if($server -ne "")
            {
                if(ping-server $server)
                {
                    Write-Host "Getting HBA Info from $server"
                    if($FullDetail)
                    {
                        $MyObject = CreateHBAListObj $server
                        $HBADetail = $MyObject | %{CreateHBAInfoObj $_.Host $_.PortWWN}
                        $MyObject | add-Member -Name HBADetail -type NoteProperty -Value $HBADetail -force
                        $MyObject
                    }
                    else
                    {
                        $MyObject = CreateHBAListObj $server
                        $MyObject
                    }
                }
                else
                {
                    Write-Host "$Server not Pingable `n" -foregroundcolor RED
                }
            }
        }
    }
    if($HostName)
    {
        Write-Host "Running HBA Check against Servers in $HostName"
        if(ping-server $HostName)
        {
            Write-Host "Getting HBA Info from $HostName"
            if($FullDetail)
            {
                $MyObject = CreateHBAListObj $HostName
                $HBADetail = $MyObject | %{CreateHBAInfoObj $_.Host $_.PortWWN}
                $MyObject | add-Member -Name HBADetail -type NoteProperty -Value $HBADetail -force
                $MyObject
            }
            else
            {
                $MyObject = CreateHBAListObj $HostName
                $MyObject
            }
        }
        else
        {
            Write-Host "$HostName not Pingable `n" -foregroundcolor RED
        }
    }
    Write-Host
}

VMWare and Powershell, The Early Years… The Life Before VMWare Powershell CMDLets

I am on the CTP for the VMWare Powershell Toolkit, and although I am unable to release any Information. I thought it would be a good idea to post some Powershell VMWare commands (old school) before they go live with the REAL Deal.

Hal from TechProsaic wrote a blog post here http://halr9000.com/article/445 about Using Plink to get Information about ESX and creating a custom object for the VM’s that the ESX host currently runs. I really liked the script, but I wanted a little more out of it. So I modified it (sorry Hal) and add some functionality. Below is a list of things it does.

  • Get Virtual Machines Running on ESX Host. Returns Custom Object
  • Provides a similar function to Get-Process from the ESX Host
  • Will Run a generic Command on the ESX Host
  • NOTE: At lines 16/31/62 I am having some issues with syntax highlight changing these to email addresses. Please make user the end up as $user @ $srv (no spaces)

    You can also get a working copy here http://powershellcentral.com/scripts/54

    # Invoke-VMCommand.ps1
    # Purpose     : Run a remote command and return the results
    # Requirements: plink.exe from the Putty project must be in $env:path
    # Use -help parameter for instructions

    Param (
        $VMHost,
        $username,
        $Command,
        [switch]$Help,
        [switch]$Verbose
    )

    # Obtains list of VMX (config files) corresponding to each VM on a given ESX server
    function GetVMX ($user, $pass, $srv) {
        $cmd = "plink.exe $user@$srv -pw $pass"
        $cmd += " vmware-cmd -l"
        Write-Verbose "Command line: $cmd"
        $VMList = Invoke-Expression $cmd
        $collOut = @()
        $VmList | ForEach-Object {
            $objOut = "" | Select-Object VmHost, VmName, VMXpath, HasSnapshot # create our output object with desired properties
            $objOut.VmHost = $srv
            $objOut.VMXpath = $_
            $objOut.VmName = (Split-Path $_ -Leaf) -replace ".vmx$"
            $collOut += $objOut
        }
        $collOut
    }
    function Get-ESXProcess($user, $pass, $srv){
        $cmd =  "plink.exe -t $user@$srv -pw $pass "
        $cmd += "`"ps -Af | grep `’`’`""
        Write-Verbose "Command line: $cmd"
        $results = invoke-Expression $cmd
        $colObj = @()
        foreach($result in $results)
        {
            if($result -match "^UID"){continue}
            $myobj = "" | Select-Object UID,PID,PPID,C,STIME,TTY,TIME,CMD
            $ary = $result.split([string[]]" ",[System.StringSplitOptions]::RemoveEmptyEntries)
            $myobj.UID   = $ary[0]
            $myobj.PID   = $ary[1]
            $myobj.PPID  = $ary[2]
            $myobj.C     = $ary[3]
            $myobj.STIME = $ary[4]
            $myobj.TTY   = $ary[5]
            $myobj.Time  = $ary[6]
            $proc = $null
            write-verbose "Length: $($ary.Length)"
            for($i = 7;$i -le $ary.Length;$i++)
            {
                $proc = "$proc $($ary[$i])"
                write-Verbose "Adding [$i] $($ary[$i])"
            }
            Write-Verbose "COMMAND = $proc"
            $myobj.CMD   = $proc
            $colObj += $myobj
        }
        $colObj
    }
    function RunVMCommand ($user, $pass, $srv, $vmcmd) {
        $cmd = "plink.exe $user@$srv -pw $pass "
        $cmd += "`"$vmcmd | grep `’`’`""
        Write-Verbose "Command line: $cmd"
        invoke-Expression $cmd
    }
    function GetSecurePass ($SecurePassword) {
      $Ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($SecurePassword)
      $password = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($Ptr)
      [System.Runtime.InteropServices.Marshal]::ZeroFreeCoTaskMemUnicode($Ptr)
      $password
    }

    # Returns help text
    function ShowUsage {
      $helptext = @"

    Invoke-VMCommand
      Requirements: plink.exe from the Putty project must be in your Path

    INPUT:

      VMHost     : name or IP of ESX server(s) (REQUIRED)
      UserName   : User to ssh With (REQUIRED)
      Command    : Command to Run. This can be a GetVMX, PSList, or a Custome String (REQUIRED)
      Help       : shows usage

    "@
      Write-Host $helptext
    }

    # Main
    if ($help) { ShowUsage; exit; }
    if ($verbose) { $verbosepreference = "continue" }

    $password = (Read-Host "Enter Password" -AsSecureString)

    if($Command -eq "GetVMX"){GetVMX $username (GetSecurePass $password) $VMHost}
    elseif($command -eq "PSList"){Get-ESXProcess $username (GetSecurePass $password) $VMHost}
    else{RunVMCommand $username (GetSecurePass $password) $VMHost $Command}

    Citrix, albeit a little slow… Gets It!

    From IForum07

    “Citrix is getting high on PowerShell and intend to rewrite the APIs to make everything available from Powershell scripting. There will be a single console, of sorts. Everything will go to MMC snap-ins, and multiple snap-ins will exist that are more task oriented, allowing you to create a MMC console with just the snap-ins you need (or all of them)”

    Full Post here: http://www.brianmadden.com/blog/iForum07/iForumApp-Delivery-Expo-Final-Notes

    As side note: Plans are in the works for a full complete set of Citrix Snapins that work off MFCom. How many would be interested even if its for a small fee?

    Error Handling: Part1 - $Error Objects

    Error handling is one thing that is not discussed as much as it should be. It is one the most important parts of working with any scripting language and in this case the interactive nature of Powershell. We have had much discussion in the IRC channel over the last couple of weeks, discussing this exact topic. So I thought I should do my best to post what I have gleaned from the discussion.

    This is one of at least a two part (maybe Three) series.
    * Error Handling: Part1 - $Error Objects
    * Error Handling: Part2 - Throw “A word about Trapping”
    * Error Handling: Part3 - The Power of Set-PSDebug

    Ask anyone that writes scripts. The ratio for Error correction in code is INSANE. Its almost 2/1. A 10 line script soon becomes 30 and a simple script becomes insanely complicated add to this the interactive nature of Powershell and you have the potential for many headaches. While Error handling in Powershell is far superior than anything to date… it still has some qwerks. I will do my best to cover some of these. Before we proceed from here, It is VERY important that you understand scope. I started to write this up, but to be honest, I think the Powershell team did a great job here. Please take some time to read the about file for scope.
    PS> get-help about_Scope

    Now, lets start off with some of the basics:

    There are several built-in objects in powershell that control and provide information about Errors
    $Error
    > This is a object that stores an array of RICH Error objects
    > Type: System.Management.Automation.ErrorRecord
    $MaximumErrorCount:
    > Total number of ErrorRecord objects that will be saved in $error
    $LASTEXITCODE
    > Exit Code of the Last script or native command than ran (i.e. ping.exe)
    > This does NOT include cmdlets
    $?
    > Boolean Value that is $false if an error occured on the last command.
    $ErrorActionPreference
    > Determines the Default action if error is thrown
    > Type System.Management.Automation.ActionPreference
    > Continue: Outputs error, but keeps processing
    > SilentlyContinue: No output and it keeps going
    > Inquire: Prompt user for action
    > Stop: Outputs error and halts processing
    $ErrorView
    > This is how the error will output to the screen
    > This truly is a variable and can contain anything, but will use NormalView if anything other than CategoryView is the value
    > NormalView: Default. Outputs semi-verbose description,Line Number, and character
    > CategoryView: Only displayes the category the error is in.

    Now that we have an overview of the objects that make up the error environment in Powershell lets deep dive into a couple of the more important ones.

    $Error: This is by far the object with the most amount of data… it really does contain pretty much everything you could possibly want to know about an error. It is important to realize that this is truly an object. It has properties, methods, and even a Type just as all the other objects have. You can see this by piping $error to get-member

    PS&gt; $error | get-member
       TypeName: System.Management.Automation.ErrorRecord

    Name                      MemberType Definition
    ====                      ========   ========
    Equals                    Method     System.Boolean Equals(Object obj)
    GetHashCode               Method     System.Int32 GetHashCode()
    GetObjectData             Method     System.Void GetObjectData(SerializationInfo info, StreamingContext context)
    GetType                   Method     System.Type GetType()
    get_CategoryInfo          Method     System.Management.Automation.ErrorCategoryInfo get_CategoryInfo()
    get_ErrorDetails          Method     System.Management.Automation.ErrorDetails get_ErrorDetails()
    get_Exception             Method     System.Exception get_Exception()
    get_FullyQualifiedErrorId Method     System.String get_FullyQualifiedErrorId()
    get_InvocationInfo        Method     System.Management.Automation.InvocationInfo get_InvocationInfo()
    get_TargetObject          Method     System.Object get_TargetObject()
    set_ErrorDetails          Method     System.Void set_ErrorDetails(ErrorDetails value)
    ToString                  Method     System.String ToString()
    CategoryInfo              Property   System.Management.Automation.ErrorCategoryInfo CategoryInfo {get;}
    ErrorDetails              Property   System.Management.Automation.ErrorDetails ErrorDetails {get;set;}
    Exception                 Property   System.Exception Exception {get;}
    FullyQualifiedErrorId     Property   System.String FullyQualifiedErrorId {get;}
    InvocationInfo            Property   System.Management.Automation.InvocationInfo InvocationInfo {get;}
    TargetObject              Property   System.Object TargetObject {get;}

    Note: Because $error is an array it inherits from [System.Array] and its methods. Clear() is the most notable.

    I could probably do a whole post on just $error, but that is beyond the scope of this one so I want just cover a few properties and one method
    ErrorDetails
    > This provides the Details of the Error. I wanted to note this is often blank
    Exception
    > This is the actual exception that was thrown
    > This is an object so it will have properties and methods of its own.
    TargetObject
    > This is the object that operation was being performed when the error occured.
    InvocationInfo
    > This contains detail information about the command that was run (i.e. Line Number, CMDlet, and Position)
    Clear()
    > This method clears the $error array.

    More Info: http://msdn2.microsoft.com/en-us/library/system.management.automation.errorrecord.aspx

    $ErrorActionPreference: I would say this is the second most important object for error handling. I have personally seen this question posted at least 10 times on the News Groups, “What is the powershell equivalent to “On Error Resume Next.” The answer lies in this object more specifically by setting $ErrorActionPreference to “SilentlyContinue.” One thing I would like to point out about this particular object is that it is scope specific. This is very important to understand. Learning to control error action at the lowest level is key to writing good scripts and knowing the state of this object can save you a ton of heartache. I cant tell you how many times I beat my head against the wall trying to figure out why I wasnt getting any error information… hmmm, $erroractionpreference set to “SilentlyContinue,” maybe that is the problem.

    More Info Here: http://msdn2.microsoft.com/en-us/library/system.management.automation.actionpreference.aspx

    In Summary, I think this a good overview of the Error Variables/Objects that you have access to, but it really only scratches the surface. I would suggest spending some time on MSDN looking through system.management.automation Namespace and get a good idea of all the information there.

    Backup-EventLog

    ## UPDATED… ADDED a EVT format Script as Well ##

    I saw a post on EE that backups up the eventlogs on Server using VBScript… I wanted to see what I could do with Powershell and this is what I came up with. I put this together pretty quick, so not much Error checking or anything, but the vbscript was 207 lines long without comments.

    Basically it does the following
    - Takes a BackupLoccation as a Parameter
    - Takes a List file or a -FromAD switch
    - List gets the computers from a file
    - FromAD gets computers from AD
    - Creates a Backup folder Named -Logs-
    - Like Server1-Logs-09110750
    - Processes Each Event Log and backs up to a File
    - Clears Log
    - I put the output of the script on the bottom.
    - NOTE: Security Logs Take awhile. I assume this because I am Generating Events by Reading the Log.

    Param($BackupLocation,$list,$FromAD)
    function Get-ADComputers{
        $filter = "(&(objectcategory=computer))"
        $root = [ADSI]""
        $props = "dNSHostName","sAMAccountName"
        $Searcher = new-Object System.DirectoryServices.DirectorySearcher($root,$filter,$props)
        $Searcher.PageSize = 1000
        $Computers = $Searcher.findAll() | %{$_.properties[‘dnshostname’]}
        $Computers
    }
    function Ping-Server {
       Param([string]$server)
       $pingresult = Get-WmiObject win32_pingstatus -f "address=’$Server’"
       if($pingresult.statuscode -eq 0) {$true} else {$false}
    }

    if($FromAD){$computers = Get-ADComputers}
    else{if($list){$computers = get-Content $list}else{Write-Host "Please Provide List";return}}

    foreach($computer in $computers)
    {
        $Folder = "{2}\{1}-Logs-{0:MMddyymm}" -f [DateTime]::now,$computer,$backupLocation
        Write-Host "+ Processing Server $Computer"
        new-Item $folder -type Directory -force  | out-Null

        if(Ping-Server $computer)
        {
            Write-Host "  + Created Backup Folder $folder"
            $eventlogs = [System.Diagnostics.EventLog]::GetEventLogs($computer)
            foreach($log in $eventlogs)
            {
                $LogFile = "{0}\{1}.csv" -f $Folder,$log.Log
                Write-Host "  + Processing $($log.Log) Log"
                Write-Host "    - Backing up $($log.Log)"
                $logEntries = $log.Entries | %{"{0},{1},{2},{3},{4}" -f $_.TimeGenerated,$_.EntryType,$_.Source,$_.EventID,$_.Message}
                $logEntries | out-File $LogFile -enc ASCII -width 500
                Write-Host "    - Backed up to $logFile"
                Write-Host "    - Clearing Log $($Log.Log)"
                $log.Clear()
            }
            Write-Host
        }
        else
        {
            Write-Host "Server $Computer failed PING!" -foregroundcolor red
        }
    }

    For those that perfer EVT format and WMI…. I left the Clear part commented

    Param($BackupLocation,$list,$FromAD)

    function Get-ADComputers{
        $filter = "(&(objectcategory=computer))"
        $root = [ADSI]""
        $props = "dNSHostName","sAMAccountName"
        $Searcher = new-Object System.DirectoryServices.DirectorySearcher($root,$filter,$props)
        $Searcher.PageSize = 1000
        $Computers = $Searcher.findAll() | %{$_.properties[‘dnshostname’]}
        $Computers
    }
    function Ping-Server {
       Param([string]$server)
       $pingresult = Get-WmiObject win32_pingstatus -f "address=’$Server’"
       if($pingresult.statuscode -eq 0) {$true} else {$false}
    }

    if($FromAD){$computers = Get-ADComputers}
    else{if($list){$computers = get-Content $list}else{Write-Host "Please Provide List";return}}

    foreach($computer in $computers)
    {
        if(ping-server $computer)
        {
            $Folder = "{1}-Logs-{0:MMddyymm}" -f [DateTime]::now,$computer
            Write-Host "+ Processing Server $Computer"
            New-Item "$backupLocation\$folder" -type Directory -force  | out-Null
            If(!(Test-Path "\\$computer\c$\LogBackups")){New-Item "\\$computer\c$\LogBackups" -type Directory -force | out-Null}
            $Eventlogs = Get-WmiObject Win32_NTEventLogFile -ComputerName $computer
            Foreach($log in $EventLogs)
            {
                $path = "\\{0}\c$\LogBackups\{1}.evt" -f $Computer,$log.LogFileName
                $result = ($log.BackupEventLog($path)).ReturnValue
                Copy-Item $path -dest "$backupLocation\$folder" -force
                #if($result -eq 0){$log.ClearEventLog()}
            }
        }
    }

    NOTE: Shortly after writing this… I found this little tibit… it seems to have been around since SP3 of Win2000

    Found it Here
    http://blogs.msdn.com/spatdsg/default.aspx

    AutoBackupLogFiles - backs up the event logs “Using this entry causes the Event Log service to automatically clear a full event log and to back up the log file. ”
    http://support.microsoft.com/kb/312571

    The Power of -f. The Format Operator

    This is from a NG post discussing the -f Operator… I thought it was a pretty good description. Compliments to Kiron.

    Q: What is the -f operator

    A: PowerShell’s Format Operator ‘-f’ is equivalent to .Net’s Composite
    Formatting. The syntax is:
    {index[,alignment][:formatString]} -f listOfValues

    Composite Formatting
    http://msdn2.microsoft.com/en-us/library/txafckwd(vs.71).aspx

    Quoting from about_operator:
    Format Operator “-f”
    The format operator provides support for formatting strings via the .NET
    string object format method. On the left hand side of the operator is the
    format string and on the right hand of the operator is the collection of
    objects to be formatted.
    The following example shows some of the capabilities of the format operator.
    PS> “{0} {1,-10} {2:N}” -f 1,”hello”,[math]::pi
    1 hello 3.14

    Some samples:

    # the ‘|’ is for demonstrating the alignment
    "{0:(###) ###-####}" -f 2224445555 # phone number
    "{0:hh:mm:ss tt}" -f (get-date) # time, 12 hour format
    "{0:HH:mm:ss}" -f (get-date) # time, 24 hour format
    "{0:p4}" -f (1/3) # percent with four decimal places
    "{0:c2}" -f (1724.87 * 12) # currency with two decimal places
    "|{0,22:c2}|" -f (1724.87 * 12) # right aligned currency with two decimal places
    "|{0,-22:n2}|" -f (13/57) # left aligned number with two decimal places
    "{0:MM dd yy}" -f (get-date) # date, custom short format
    "{0:MMMM yyyy}" -f (get-date) # date, ‘month year’ format
    0..15 | % {"{0:0##}" -f $_} # filled number format
    0..15 | % {"|{0,33}|" -f "Number $_"} # right aligned string
    0..15 | % {"|{0,-33}|" -f "Number $_"} # left aligned string
    0..15 | % {"|{0,33}|  |{0,-33}|" -f "Number $_"} # right & left aligned string

    Suggested Reading.

    Standard Numeric Format Strings
    http://msdn2.microsoft.com/en-us/library/dwhawy9k.aspx

    Custom Numeric Format Strings
    http://msdn2.microsoft.com/en-us/library/0c899ak8.aspx

    Standard DateTime Format Strings
    http://msdn2.microsoft.com/en-us/library/az4se3k1.aspx

    Custom DateTime Format Strings
    http://msdn2.microsoft.com/en-us/library/8kb3ddd4.aspx

    Enumeration Format Strings
    http://msdn2.microsoft.com/en-us/library/c3s1ez6e.aspx

    Check out this blog from the PowerShell Team
    http://blogs.msdn.com/powershell/archive/2006/06/16/634575.aspx

    Script to set the Description of Computer Object

    I recently joined Experts-Exchange to help people understand the glory of Powershell and how useful it can be to your average Server Admin with little to no scripting or developer experience and trying to sell the idea you do NOT have to be a Developer or hard core scripter to utilize the power that is at your finger tips.

    In one of my 200+ response post in the last week :) An admin wanted to collect data from all the servers/workstations in his environment. What was so fun to watch was how Powershell DESTROYED vbscript and I didnt really take an shortcuts.

    Total Line Count Vbscript = 98
    Total Line Count Powershell = 53

    Effectively what it does is collect hardware info from the server/workstation and updates AD Descript field with the data as well as export the info to .CSV file

    CPU 3.20GHz/2GB Ram/69,845GB/1.44/CDD

    Here is the code.
    Download here http://bsonposh.com/uploads/wordpress/2007/08/Set-ComputerDescription.ps1

    $Servers = Get-Content "C:\computers.txt"
    $myobjects = @()
    foreach($server in $servers)
    {
        write-host "Processing Server $server"
        $query = "Select statuscode FROM Win32_PingStatus WHERE Address=’$server’ and Timeout=300"
        $pingresult = Get-WmiObject -query $query
        if($pingresult.statuscode -eq 0)
        {
            $myobj = "" | Select Name,CPU,Memory,DiskSpace,CD,Floppy
            $myobj.Name = $server

            # Getting Computer Object
            $filter = "(&(objectcategory=computer)(cn=$server))"
            $ds = new-Object System.DirectoryServices.DirectorySearcher($filter)
            $comp = ($ds.findone()).GetDirectoryEntry()

            # CPU info
            $cpu = Get-WmiObject Win32_Processor -computername $serv