Search This Blog

Friday, 20 May 2016

PowerShell - Outputting PowerShell error text to log file

Seeing the red in black and white

The Idea

I'm trying to build an after-OS install deployment script that creates a log file when initiated and tracks the changes, successes and failures, during the deployment process, peeking back to see how far it's got so I can basically select from a defined set of configurations and leave the script to finish the job. The key requirements are that the script is highly compatible, so PowerShell v2 is the target. The script has to bypass common security dialogs for installers so the script is launched with the command PowerShell -ExecutionPolicy Bypass -File "%~dp0%thisScript%" and is lanuched as an administrator.

The Issue

The script output must be shown both in the command window and copied to a text file simply so I can see if anything went wrong without having to carefully examine the output of a command line window precariously left on a "press any key...", but can still see both the command line output in action in the window explaining where I am in the deployment process while the script is in action and check the log file at the end for error. Due to the fact that the script itself is designed to deploy various individual installers, it should record errors but not break on them unless critical. This can be handled through both capturing exit codes from installers and handling WMI queries in try catch code blocks.

I'm using command line to start the script and although I can redirect the output of the script launching command to a text file using something like:
PowerShell -ExecutionPolicy Bypass -File "%~dp0%thisScript%" > C:\Logs\ThisScript.txt
This would stop the console displaying the output of the script in the command window. The script would still run and be logged completely, but you wouldn't be able to see it processing the tasks.

I Did This

Being that PowerShell allows for "modules" (either scripts or compiled dlls), it seems logical to create a logging script module that I can throw objects down the pipeline which I can reuse in other scripts by calling the Import-Module cmdlet. This is a little complicated module and is still a work in progress.



Pretty nasty code alert:

[bool]$LogToFile = $False
$cDT = Get-Date
[string]$LogFilePath = ('{0}\Logs\ANOVO\{1}_ScriptLog.log' -f "$env:windir", ('{0}-{1:D2}-{2:D2}_{3:D2}-{4:D2}' -f $cDT.Year, $cDT.Month, $cDT.Day, $cDT.Hour, $cDT.Minute))
[bool]$EchoLog = $True
[bool]$LogMessagePassThru = $False

function Write-LogFile {
    param(
        [parameter(ValueFromPipeline=$True,
        HelpMessage='Enter message to write to log file.')][string]$logMessage,
        [parameter(Mandatory=$False,
        HelpMessage='Enter title for log file message.')][string]$logTitle = 'Log Entry',
        [parameter(Mandatory=$False,
        HelpMessage='Enter full path for log file.')][AllowEmptyString()][string]$logPath,
        [parameter(Mandatory=$False,
        HelpMessage='Allow pipeline message to pass through.')][bool]$logPassThru = $script:LogMessagePassThru
    )
    Begin {
    }
    Process {
        if($LogToFile)
        {
            if(($logPath -eq $null) -OR ($logPath.Length -lt 1)) { $logPath = $script:LogFilePath }

            if(!(Test-Path (Split-Path -Parent $logPath))) {
                New-Item -ItemType Directory -Force -Path (Split-Path -Parent $logPath) | Write-LogFile -logTitle 'Logs Directory Created' -logPath $logPath -logPassThru $False
            }
            if(!(Test-Path $logPath)){
                New-Item -ItemType File -Force -Path $logPath | Write-LogFile -logTitle 'Log File Created' -logPath $logPath -logPassThru $False
            }

            ('[{0} - {1}] {2}: {3}' -f (Get-Date).ToShortDateString(), (Get-Date).ToLongTimeString(), $logTitle, $logMessage) | Out-File $logPath -Append -Force
        }

        if($logPassThru) { $logMessage }
        else
        {
            if($EchoLog)
            {
                ('[{0} - {1}] {2}: {3}' -f (Get-Date).ToShortDateString(), (Get-Date).ToLongTimeString(), $logTitle, $logMessage) | Out-Host
            }
        }
    }
    End{
    }
}

Export-ModuleMember -Function Write-LogFile

Export-ModuleMember -Variable LogFilePath
Export-ModuleMember -Variable LogToFile
Export-ModuleMember -Variable EchoLog
Export-ModuleMember -Variable LogPassThru

The Problem

The key issue I wanted to resolve was how to get the PowerShell red failure text to copy to the log file. It's actually quite readable and if nothing more, reports the point of failure the script quite noticeably when reading through a large log file. Also, I needed to have the text captured on commands and installers that may fail. Errors in PowerShell can come from multiple angles (installers, powershell commands, WMI object functions and more) and handling these isn't uniform. Sometimes, a function call may fail, but not output an error or may completely fail and stop the script.

My Solution

I set up a quick check using the $? operator, $Error[] array and catching the last output.

Write-LogFile "Beginning function..."
Preform some object function that may fail but not report it here
if($?)
{
  Write-LogFile 'This was successful.'
}
else
{
   Write-LogFile "This was not: $Error[0]"
} And...

Write-LogFile "Something may break here..."
try
{
  Preform something that could cause powershell to red text
}
catch
{
  Write-LogFile 'You broke it!'
  Write-LogFile 'Powershell Error Message:'
  Write-LogFile $_
}
When we do this, the full error text shows up in both the command line window and in the log file, allowing the script to continue. If you don't wan to capture the fully qualified error, you can just caputre the general message with $Error[0].Exception.Message




Code and output:
PS C:\>
try
{
  MakingSomething-Up
  Write-Output 'Successfull.'
}
catch
{
  # $thisError = $Error[0].Exception.Message
  Write-Output 'Failed.'
  Write-Output 'Powershell Error Message:'
  Write-Output $_
}

Write-Output 'Reached this too...'
Failed.
Powershell Error Message:
MakingSomething-Up : The term 'MakingSomething-Up' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a
path was included, verify that the path is correct and try again.
At line:4 char:3
+   MakingSomething-Up
+   ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (MakingSomething-Up:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Reached this too...

PS C:\>

Thursday, 19 May 2016

dotNet File Hash - Work in Progress

dotNet File Hash

Why?

I was dissatisfied with a lot of "duplicate finder" applications showing various inconsistencies from being too accepting ("This picture, kind of looks like that one") or too unforgiving ("This file has a different creation date so it must be different"). The key functionality I was looking for is file content comparison without taking into account additional extended data applied by filesystem or OS. File hashing seemed like the most logical course, and, thanks to Google and the open source community, there were many good examples for me to get started from...

What?

This is a C# .Net 4.0 file hashing Windows application that implements a variety of hashing algorithms (MD5, SHA1, SHA256, SHA384, SHA512, RIPEMD160) readily available in the System.Security.Cryptography section of the .Net framework and can be used to compare files from various folders for true file duplications by directly hashing the content and ignoring other extended details.

I've started to add extra stuff like saving of hash lists and some light theming (check preferences), but this application is not finished and should be considered "alpha" software. At the moment, due to the way I calculate duplicates (MD5+SHA1), there is a mathematically ridiculously small probability of a false duplicate (Birthday Paradox and whatnot) so check your selection before deleting (not implemented yet) anything. As always, use this at your own risk, but if you feel unsure, read through the code.
 
The application UI is pretty crude, but the underlying code is quite lean. As always, this application is an example project for other users to take the code from and use as they please according to the GNU GPL V3 license referenced within the application.

License

GNU GPL V3

Requirements

OS: Windows XP or betterMicrosoft .Net framework v 4.0 or better

Main Window

 

 Preferences

 

Duplicate Highlighting - Hide Unique


Show Only Duplicates

 

File Grouping and Duplicate Count for group

 

Project Page

https://sourceforge.net/projects/dotnet-file-hash/

Wednesday, 18 May 2016

Stranded 2 Mod Viewer - My addition to an awesome if aged game

Stranded II Mod Viewer

Why?

When I was growing, a fantastic step in understanding various 3D modelling file formats came in the form of an open source first person shooter survival and crafting game that stole my heart for its simplicity yet versatility. This was Stranded 2. I played this game for months before the sheer difficulty of trying to discover undocumented functions led me to joining the forum and found that much of the game is deliberately undocumented. Not only that, the game allows for large scale modifications of the game via rescripting of the game files that are simple text files but in a new and interesting way. This meant that there were many mods of the game which greatly expanded on the original experience and were worthwhile playing that still suffered from the same lack of documentation and held me back in the original. So I started working on a solution.

Originally, I just wanted to create something to tell me what items I needed to combine to get better items without asking on the forum or trawling through stale text files...

What?

With the help of DC, the game creator and Builder, the creator of "Massive Mod", I have created an application that reads the game files of most mods (dependant on both complexity and poor scripting). It can detect and inform of some basic errors in the game files, helping modders refine their mods. It also gives an informative display of the items, objects, buildings, combinations and units so new players might find this useful as a guiding tool. I've also included intuitive controls for navigating around different pages and objects,  custom columns with item count, ID, effects and more are displayed in a simplistic and easy to read way.

License

GNU GPL V3

Requirements

OS: Windows XP or betterMicrosoft .Net framework v 4.0 or better

Items View

Combinations View

 

Buildings View


Project Page

https://sourceforge.net/projects/stranded-ii-mod-viewer/

Tuesday, 17 May 2016

PsyPlay - My FOSS C# Media Player using Direct X as a display interface

PsyPlay

Why?

I was getting into Windows forms programming in C# (.Net 3.5) and was interested in how I could make a simplistic media player that operated with the system installed codecs for media. Straight up, I'm not good enough to import and start handling loads of different FOSS codecs; I can barely program, but I thought that it had to be possible, so with a little bit of Googling DirectX C# implementations, I started a basic window... It kind of grew from that...


What?

It's a bare simple media player with a laughable amount of "theming" capabilities but it functions, has some cool options like real file drag and drop into other applications (warning, this can move files), a media library function, video capabilities with full screen, keyboard controls etc. More than anything, this is an example project I made years ago to demonstrate DirectX in C# which is probably fairly outdated now, but due to .Net compatibility, may be relevant to some.

 

License

GNU GPL v3

Requirements

OS: Windows XP or better
Microsoft .Net 3.5 Framework (up to 3.5.1)

Main Player

 

Video

 

Media Library

 

Project Page

https://sourceforge.net/projects/psyplay/

Monday, 16 May 2016

ISESteroids - Exhaling from the complication of PowerShell version control

ISESteroids

How I found...

Backstory - Tl;Dr - I stumbled into coding

For the purpose of this article, I would describe myself as a power user with added Google, not a programmer, technician or any other title that would insinuate I have had any form of structured training in creating programmatic solutions. I'm just a guy who grew up in PCs; playing with them, fixing them, sleeping on them. I am by no means methodical in my programming and scripting. I approach new languages by having a goal in mind and acquire only the necessary information to achieve this, which gives some bare understanding but always a poor foundation that eventually becomes more established as the use of the language becomes more required. It's a bad way of learning for various reasons, but I find it allows you to easily change your understanding of the language in an instant. So I can barely read ASM, barely code in C, code console applications in C++ and can program various windows applications in C#. There's some batch scripting in there, VBscript and now PowerShell.

The main thing I learned from this is that most goals are achiveable by using any of the languages, but the caveats of each method and language make them particularly well suited to one type of task or another. You can have developers toss around jargon about who's language is better but languages aren't created for fun (well, yes but no). Lots of people have spent a long time making a defined language, getting it established and giving it relevance. They're created with intent and that makes them tuned. Knowing which one suits your purpose is half the battle.

The Project - Help People

I help people with PCs. Possibly out of a sense of duty, probably out of ego, definitely with one intent; Make the user more comfortable. Not just content, but with a sense of security. This is why I back up Windows installations and advise personal data be stored on other medium than your operating system disk. Still, this does not prevent people laying waste to their OS and possibly the disk. Although there are a few recovery techniques available to recover even the severest of data loss, there is no guarantee that any method will work and usually results in a full reinstallation of the OS and associated applications anyway. The faster you can make this happen, the generally more comfortable people are.

Whenever I find myself repeating anything in computing, there's probably a way to automate it, and in this case, the method is clearly scripting. Creating a program to do the install of multiple applications and system setting configurations can be done, but due to the simplicity of editing, the ease of flexibility and the general ability to handle various types of installers with their own quirks, scripts work for me.

PowerShell, how your versions aggrivate me so

Batch was the boy back in the day when I was a boy for handling Windows OS and even today, due to the sheer simplicity, lots of IT professionals rely on batch scripts, usually and ironically to launch other types of scripts (I use a batch to start a PowerShell script). The the age old and still thriving start of my scripting life has evolved through various new implementations for greater system control (VBScript) and updated with a greatly expanded set of system interfaces (PowerShell). I love the greater flexibility in controlling the all aspects of the operating system and the language is strangely asthetically pleasing, but now I find myself knee deep in the "pipeline" getting pounded by unknown object types. Microsoft have provided a good integrated scripting environment (ISE) for PowerShell, but jeez, it's bare.

 

Steroids?? Ok...

This is the 4th iteration of PowerShell I'm using  and it still feels a bit lacklustre. The bare essentials are there for a scripting environment; coloured highlighting and intellisense (auto-complete :P) but still, in terms of error checking and debugging, you're usually on your own. This can leave you resorting to trial and error of scripts and entering commands every time you need to pull up help or running tandem with a browser. Some of these are more serious than others but the straw that made me seek a better alternative was version control. How could I tell if my scripts would run on a PC with only PowerShell v2, or if other apps are called in? The time and effort it would take to research the compatibility of every command in my scripts and modules could take me a lifetime, or at least feel like it, so I looked for something that could provide the most needed aspect... Luckily, it came with much more. Enter ISESteroids.


Getting Started With ISESteroids

Installing

This was slick. If you have PowerShell v5, you can just open the normal ISE and type some commands (available on their downloads page). As I'm poorer, I got the download package.

It was a case of unzip, click install.bat, start the ISE and type "Start-Steroids"... And thats it...

Can't fault it for simplicity and there are instructions on how to make it load with the ISE, but that choice is up to you. I like having the option to step up to for full editing and bare ISE for quick typos (What? They happen...).

The UI

It gave me a wonderfully warm reminder of the time as it began initialising.
 

Then the UI with an array of new buttons.


Jumping straight in

Immeditately, it felt like what I was hoping for. A familiar interface with more control. So I loaded a script and opened the new "Context Sensitive Help Add-On" which I was excited to read about on their reviews. This wonderful little thing grabs relevant help to whatever is selected in the scripting window.
 

The squiggly line shows me where an error exists or simply better writing could be used. That was particularly useful in scripts where I'd used the "Where" alias everywhere, wheras a more compatible "Where-Object" would be better. So when I selected and hovered over the squiggly line under a string I'd written in this script, the side bar displayed information about what I selected and the popup told me that using single quotes would be better practice. Very cool for my learning curve. Even better, if you follow the line with the correction to the left edge, there's a lightbulb icon that, when clicked, will correct all this type of correction in the entire script.

 

So with automatic script fixes and real-time context sensitive help, I can see the value in this. After making the correction, the help panel updated.

 

Solving the problem

The main reason I'd got this was to see if something very important worked. This was version checking. In my version, this was in the "Compatibility" section of the main menu strip.

 

It was only then that I also stumbled across the "Create Compatibility Report" function which does exactly as it says, giving a list of all the dependancies your script has to outside objects such as other modules, executables and more. The only thing that came back on mine was references to my other modules.

 

Summary

There's no doubt that this software has some real power under the hood, adding so much that I haven't mentioned and resolving a lot of the pet hates I had when working with PowerShell. If you're working with PowerShell intensively, either as a hobbyist or a professional, I would advise at least taking the free 10-day trial just to see what it can do for you. ISESteroids has helped me correct and refine much of my poor scripting, it's gonna be hard to go back to anything else.

Nice work, problem solved.