::::::::: PowerShell :::::::::
Monday, February 27, 2006
  [MSH] Displaying Zip File contents
Let's have some fun with zip files.

I have searched through MSDN document on whether .NET library but could not finddd
any C#/VB.net library that deals with Zip file content.

I have been googling around the web but found a useful J# library for dealing with
zip files easily. The name of J# library is called "VJSLIB.DLL".

Here is the step on how to get a Zip file content

  1. Open "java.io.FileInputStream" for a zip file

  2. Pipe File Input stream object to "java.io.ZipInputStream"

  3. While there exists a content in a zip input stream, get a content of type "ZipEntry"

  4. Close "ZipInputStream" first and then "FileInputStream"



# Author: DBMwS
# Date: 02/27/2006 @ 04:13 PM EST
# Description: Retrieve a Zip file's content
# (either display only files inside the zip file or return ZipEntry object)
# Note: This function requires J# Library, "vjslib"
# Usage: get-ZipContent file_name [[System.Bool] -toString]
# Reference: http://codeproject.com/csharp/VmEasyZipUnZip.asp
# Params
# 1) $zipFileName: Path of zip file
# 2) $toString: return name of zip content, otherwise return ZipEntry
function Get-ZipContent {
param($zipFileName = $(throw "Enter Zip File Name"), [bool]$toString = $true)

# Load J# library
# used "out-null" instead of "[void]" since "out-null" would not display
# loaded assembly even if there was an exception thrown
[System.Reflection.Assembly]::LoadWithPartialName("vjslib") | out-null

# 1) Open "java.io.FileInputStream" for a zip file
$fis = new-object java.io.FileInputStream($zipFileName)
# 2) Pipe File Input stream object to "java.io.ZipInputStream"
$zis = new-object java.util.zip.ZipInputStream($fis)

# 3) While there exists a content in a zip input stream, get a content of type "ZipEntry"
while (($ze = $zis.getNextEntry()) -ne $null) {
if ($toString) {
# Pass string value to pipe
Write-Object $ze.ToString()
} else {
# Pass actualy ZipEntry object to pipe
$ze
}
}

# 4) Close "ZipInputStream" first and then "FileInputStream"
$zis.close()
$fis.close()

trap {
if ($zis -ne $null) { $zis.close() }
if ($fis -ne $null) { $fis.close() }
break
}
}
It is still not complete since, it does not list a zip file inside a given zip file name(no recursive listing)
But I have left that part out on purpose since "get-ZipContent" can be called recursively in a while loop in another function.

Here is how one can utilize "Get-ZipContent"

MSH>ls | where {!$_.MshIsContainer -and $_.name -like "*.zip"} | foreach { get-zipcontent $_.fullname } | where { $_ -like "*.jpg" }


In above code snippet, i have used "where {!$_.MshIsContainer -and $_.name -like "*.zip"}" to filter out directories and select files with only "*.zip" extension
(Well, if you don't filter out files that way, get-ZipContent would fail half way when a directory or a non-zip file has been passed to it)

Well, I will be talking about how to actually "extract" the contents in the next blog.

EDIT: Tested under both Monad v3.0 & v3.1 ;) Refer to /\/\o\/\/'s blog on Beta v3.1 release here



Reference: Zip and Unzip from a C# program using J# runtime by Valeri

Tags :
 
Saturday, February 25, 2006
  [MSH] MSH Analyzer
Well, Karl Prosser has create his own GUI Msh hosting environment.
I think it's still in pre-alpha status(well Karl calls it a "Proof of Concept" stage)

It supports both one-line and multi-line command support and automatically dumps returned objects' class information. In the current screenshot on his site, you don't see "XML" table, but if you do something like



$xml = [xml]"<xml><title>some title</title><name>some name</name></xml>"
$xml


You can see parsed xml data as you see in Internet explorer.
Well, just try it out yourself.

Go download the executable file here
 
Wednesday, February 22, 2006
  [MSH] How to a[void] returning multiple values from a function
I have succesfully made one of C# application I was working on at work to call MSH script on the fly during runtime. Everything seemed to have been working fine until I have encounted this problem that MSH functions can return mutiple values I have passed a variable named $arr of type System.Collections.ArrayList to the Msh Script through
Runspace rs = RunspaceFactory.CreateRunspace();
rs.SessionStateProxy.SetVariable("arr", new ArrayList());
/*** snip ***/
string cmd = ". .\\parse-file.msh";
Pipeline pl = rs.CreatePipeline(cmd);
From here on, a variable named $arr is visible in "parse-file.msh".

Now in "parse-file.msh" script, I tried something like(NOTE: In actual "parse-file.msh", there is no initialization code for $arr to ArrayList, in the following function, $arr are initialized as a demonstrative purpose only, /\/\o\/\/, I have cleared it up here :))

MSH>function bar {
>> $arr = new-object System.Collections.ArrayList
>> $arr.Add(1)
>> $arr.Add(2)
>> $arr.Add(3)
>>
>> return $arr
>> }
>>
MSH>bar
0
1
2
1
2
3


And the function returns 4 values, 3 int32 values and 1 3-element ArrayList object, instead of just the contents of $arr.
We can confirm that through the following snippet

MSH>function multiple-returns {
>> $arr = new-object System.Collections.ArrayList
>> $arr.Add(5)
>> $arr.Add(6)
>> $arr.Add(7)
>> return $arr}
>>
MSH>multiple-returns
0
1
2
5
6
7
MSH>$a, $b, $c, $d, $e = multiple-returns
MSH>$a
0
MSH>$b
1
MSH>$c
2
MSH>$d
5
6
7
MSH>$e
MSH>$d.getType().Name
ArrayList
MSH>$e.getType().Name
You cannot call a method on a null-valued expression.
At line:1 char:11
+ $e.getType( <<<< ).Name


First 3 return values(0, 1, 2) were caused by the fact that ArrayList returns "index at which the value has been added".
Well, But then, what if you don't actually want to return indexes at which value has been added?

There are two choices(and as far as I understand, they work about the same although the background principle is different)
*EDIT*: there are 3 choices( Thanks /\/\o\/\/ for another solution :), Check out "comments" section )

  1. [void]

  2. out-null

  3. > $null



[void] in front of a method indicates that, the method does not return a value.
For example, try out the following(yes, do try them out!)
MSH>[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

GAC Version Location
--- ------- --------
True v2.0.50727 C:\WINDOWS\assembly\GAC_MSIL\System.Windows.Forms\2.0.0.0__b77a5c561934e08...
MSH>[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
MSH>[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | out-null
MSH>[System.Reflection.Assembly]::LoadWithPartialName("system.windows.forms") >$null
MSH>

Let's see what just happened

Now Let's revise the function "bar".

MSH>function bar {
>> $arr = new-object System.Collections.ArrayList
>> [void]$arr.Add(1)
>> [void]$arr.Add(2)
>> [void]$arr.Add(3)
>>
>> return $arr
>> }
>>
MSH>bar
1
2
3

MSH>function bar {
>> $arr = new-object System.Collections.ArrayList
>> $arr.Add(1) | out-null
>> $arr.Add(2) | out-null
>> $arr.Add(3) | out-null
>>
>> return $arr
>> }
>>
MSH>bar
1
2
3



Now those functions did not return added index positions during "ArrayList.Add" operations.
I tend to go with [void] since it sounds technically right to mark(or cast, not sure about how to call it) a method as not returning any value


Tags :
 
Tuesday, February 21, 2006
  Blogger and Technoroti problem
Well, it seems like a lot of people's updated Blogger posts are not being updated in Technorati because of some problem on Blogger.com

I have seemed to fixed it by going to my Technorati account -> Your Blogs -> View & Edit Blog All Blog Info -> Update Ping

It was kind of annoying not to be able to see other MSH and Monad posts being updated :)

Tags :
 
Saturday, February 18, 2006
  [MSH] print-image *Snapin* version
During my spare time, i spent sometime converting "print-image" cmdlet into a Snapin version.

I have extended its functionality just by a tiny bit by adding "Landscape" mode printing. Well, I still haven't tried adding a "help" file yet so I will try to add one when I have more time(so for now, something like "print-image -?" will complain that cmdlet cannot find a help xml file).

Anyways, here is the usage for "print-image" for this this version.

This command also supports only one ubiquitous parameter: -Verbose(-vb)

print-image [-FileName|-fn] System.String [[-Printer|-p|-pn] System.String] [[-Landscape|-l|-ls] System.Boolean]
Where,
  1. FileName: Fully Qualified File Name

  2. Printer: Name of print to send image to

  3. Landscape: Print images in Landscape mode


Well, if you would like to change "margins", there are two options. First one is you go to your printer setting and change the margin size there, or modify the msh script to be able to receive margin data.

To retrieve available printer names on your current machine, you can load "System.Drawing" assembly and then retrieve "System.Drawing.Printing.PrinterSettings.InstalledPrinters" property like the following

MSH>[reflection.assembly]::loadwithpartialname("system.drawing")

GAC Version Location
--- ------- --------
True v2.0.50727 C:\WINDOWS\assembly\GAC_MSIL\System.Drawing\2.0.0.0__b03f5f7f11d50a3a\Syst...

MSH>[Drawing.Printing.PrinterSettings]::InstalledPrinters
Microsoft Office Document Image Writer
HP LaserJet 8150 PCL 5e
HP LaserJet 5000 Series PCL 5e
HP Color LaserJet 5500 PCL6(Color)
Adobe PDF
MSH>

and then use the printer names listed above


Here is how you can use the "print-image"
Image hosting by Photobucket

Uhm, I don't have any storage areas where I can just put my source or compiled binaries on... So, i am just pasting the source here...
using System;
using System.IO;
using System.Drawing;
using System.Drawing.Printing;

using System.ComponentModel;
using System.Management.Automation;
using System.Collections.Generic;
using System.Text;

namespace D2D.Snapins
{
/// <summary>
/// Prints image files
/// </summary>
/// <remarks>
/// @TODO: Display Preview form
/// </remarks>
[RunInstaller(true)]
public class PrintImageSnapin : MshSnapIn
{
public override string Description
{
get { return "Prints an image file"; }
}

public override string Name
{
get { return "D2D_print-image"; }
}

public override string Vendor
{
get { return "DontBotherMeWithSpam"; }
}
}

[Cmdlet("print", "image")]
public class PrintImageCommand : MshCmdlet
{
#region Private Member Variables
/// <summary>
/// Fully qualified image file name to print
/// </summary>
private string fileName;
/// <summary>
/// Name of printer to use
/// </summary>
private string printer;
/// <summary>
/// Should we use landscape mode or not
/// </summary>
private bool landscape;


/// <summary>
/// Responsible for printing image document
/// </summary>
private PrintDocument doc;

/// <summary>
/// Image to constructed from input file name
/// </summary>
private Bitmap img;

/// <summary>
/// Holds exception thrown in functions other than
/// "BeginProcessing", "EndProcessing", "ProcessRecord"
/// </summary>
private Exception ex;
#endregion

#region MSH Parameters
/// <summary>
/// Fully qualified image file name to print
/// </summary>
[Alias("fn")]
[Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true,
HelpMessage = "Fully qualified image file name to print")]
public string FileName
{
get { return this.fileName; }
set { this.fileName = value; }
}

/// <summary>
/// Name of printer to use
/// </summary>
[Alias("p", "pn")]
[Parameter(Mandatory = false, Position = 1, ValueFromPipeline = true,
HelpMessage = "Name of printer to print image")]
public string Printer
{
get { return this.printer; }
set { this.printer = value; }
}

[Alias("l", "ls")]
[Parameter(Mandatory = false, Position = 2, ValueFromPipeline = false,
HelpMessage = "Toggle Landscape mode")]
[DefaultValue(false)]
public bool Landscape
{
get { return this.landscape; }
set { this.landscape = value; }
}
#endregion

protected override void EndProcessing()
{
this.doc = new PrintDocument();

this.doc.BeginPrint += new PrintEventHandler(doc_BeginPrint);
this.doc.PrintPage += new PrintPageEventHandler(doc_PrintPage);
this.doc.EndPrint += new PrintEventHandler(doc_EndPrint);

this.doc.Print();

}

#region PrintDocument Event Handlers
/// <summary>
/// Construct image to print
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void doc_BeginPrint(object sender, PrintEventArgs e)
{
// Construct image to print
try
{
this.img = new Bitmap(this.FileName);
this.doc.DocumentName = Path.GetFileName(this.FileName);
this.doc.DefaultPageSettings.Landscape = this.Landscape;
if (this.Printer != "")
{
this.doc.PrinterSettings.PrinterName = this.Printer;
}
}
catch (Exception ex)
{
// We have failed create an image from the given file name
// No need to process any further, actually...
/// How do i abort the script at this point?
ErrorRecord err = new ErrorRecord(ex, "doc_BeginPrintError",
ErrorCategory.InvalidData, this.fileName);
WriteError(err);

e.Cancel = true; // abort printing job
}

//e.PrintAction = this.PrintAction;
e.Cancel = false;

WriteVerbose(string.Format(
"==================== {0} ====================",
this.doc.DocumentName));
}

/// <summary>
/// Print constructed image according to PrintAction
/// </summary>
private void doc_PrintPage(object sender, PrintPageEventArgs e)
{
WriteVerbose(string.Format("Printing {0}",
this.doc.DocumentName));

Graphics g = e.Graphics;
Rectangle paperBounds = e.MarginBounds;
SizeF adjSize = AdjustImageSize(this.img.Size, paperBounds);

if (this.ex == null)
{

// Calculate source and destination sizes
RectangleF destRec = new RectangleF(paperBounds.Location, adjSize);
RectangleF srcRec = new RectangleF(0, 0, img.Width, img.Height);

// Print to according to "PrintAction"
g.DrawImage(this.img, destRec, srcRec, GraphicsUnit.Pixel);
}
else
{
ErrorRecord err = new ErrorRecord(this.ex, "AdjustImageSizeError",
ErrorCategory.NotSpecified, null);
WriteError(err);
}

// Nothing else to print...
e.HasMorePages = false;
}

/// <summary>
/// Clean up used resources
/// </summary>
private void doc_EndPrint(object sender, PrintEventArgs e)
{
// Free Bitmap resource
if (this.img != null)
{
this.img.Dispose();
this.img = null;
}

WriteVerbose(string.Format(
"xxxxxxxxxxxxxxxxxxxx {0} xxxxxxxxxxxxxxxxxxxx",
this.doc.DocumentName));
}
#endregion

/// <summary>
/// Adjust image size to fit to the paper size
/// </summary>
/// <param name="imgSize">Size of image to adjust to fit to paper size</param>
/// <param name="paperBound">Bounding area of paper</param>
/// <returns>Adjusted size of image that fits on the paper</returns>
/// <remarks>If image's width is bigger than its height, try to fit width, else fit height</remarks>
private SizeF AdjustImageSize(Size imgSize, RectangleF paperBound)
{
bool fitWidth = (imgSize.Width > imgSize.Height); // Fit width or the height?
double ratio = 1;
SizeF adjSize = new SizeF(imgSize.Width, imgSize.Height); // adjusted size to return

try
{
// Image size is smaller than actual paper size to print on,
// so we use the original image's size
if ((imgSize.Width > paperBound.Width) &&
(imgSize.Height > paperBound.Height))
{
// If width is longer than the height of its image,
// we get the ratio of the width, else get the ratio of the height
if ((fitWidth == true))
{
ratio = (double)(paperBound.Width / imgSize.Height);
}
else
{
ratio = (double)(paperBound.Height / imgSize.Height);
}

adjSize = new SizeF(
// Flip the width of the image in Landscape mode
(this.Landscape ? paperBound.Height : paperBound.Width),
(float)(imgSize.Height * ratio));
}
}
catch (Exception ex)
{
this.ex = ex;
}

return adjSize;
}
}
}




Tags :
 
Tuesday, February 14, 2006
  [MSH] print-image
Your boss comes at your desk with a pile of CDs filled with high quality tiff images(roughly 20000 x 20000 pixels)
He tells you to print all the image files fit into a "letter" sized paper in 2 days

Well, that sort of stuff happend to me...

Man, was I frusted...

But that's when MSH came into rescue~
Well, the first thing that came up in my head was, "out-printer" cmdlet.
So I tried the following

MSH>$bitmap = new-object System.Drawing.Bitmap c:\test.tif
MSH>out-printer -printer "Adobe PDF" -in $bitmap


Voila. Now i was excited to see a picture in PDF format through "out-printer".
Wrong!

All I saw in the generated PDF file was

Tag :
PhysicalDimension : {Width=14454, Height=21957}
Size : {Width=14454, Height=21957}
Width : 14454
Height : 21957
HorizontalResolution : 1016
VerticalResolution : 1016
Flags : 77888
RawFormat : [ImageFormat: b96b3cb1-0728-11d3-9d7b-0000f81ef32e]
PixelFormat : Format1bppIndexed
Palette : System.Drawing.Imaging.ColorPalette
FrameDimensionsList : {7462dc86-6180-4c7e-8e3f-ee7333a7a483}
PropertyIdList : {256, 257, 258, 259, 262, 270, 273, 277, 278, 279, 282, 283, 32781}
PropertyItems : {256, 257, 258, 259, 262, 270, 273, 277, 278, 279, 282, 283, 32781}


, which is data you see just typing "MSH>$bitmap" in console.

Gosh, was I frusted, again. I looked into "out-printer" help page if there was some kind of "-encoding" option to print binary files(images) but there wans't any...

I resorted to using System.Drawing.Printing.PrintDocument

Well, using that Class, printing is an image is a breezy job
So i created a cmdlet called "print-image" which takes an image name and print it

Here is the usage of the cmdlet

print-image "image name" [printer name] [fit image to paper]


The cmdlet takes the mandatory parameter "image name" with optional printer to print to and whether image size should fit on a paper

Following is how the cmdlet can be used

MSH> ls *.tif | foreach { print-image $_ }


Well and that's exactly what i did... :)







function print-image {
param([string]$imageName = $(throw "Enter image name to print"),
[string]$printer = "",
[bool]$fitImageToPaper = $true)

trap { break; }

# check out Lee Holmes' blog(http://www.leeholmes.com/blog/HowDoIEasilyLoadAssembliesWhenLoadWithPartialNameHasBeenDeprecated.aspx)
# on how to avoid using deprecated "LoadWithPartialName" function
# To load assembly containing System.Drawing.Printing.PrintDocument
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")

# Bitmap image to use to print image
$bitmap = $null

$doc = new-object System.Drawing.Printing.PrintDocument
# if printer name not given, use default printer
if ($printer -ne "") {
$doc.PrinterSettings.PrinterName = $printer
}

$doc.DocumentName = [System.IO.Path]::GetFileName($imageName)

$doc.add_BeginPrint({
Write-Host "==================== $($doc.DocumentName) ===================="
})

# clean up after printing...
$doc.add_EndPrint({
if ($bitmap -ne $null) {
$bitmap.Dispose()
$bitmap = $null
}
Write-Host "xxxxxxxxxxxxxxxxxxxx $($doc.DocumentName) xxxxxxxxxxxxxxxxxxxx"
})

# Adjust image size to fit into paper and print image
$doc.add_PrintPage({
Write-Host "Printing $imageName..."

$g = $_.Graphics
$pageBounds = $_.MarginBounds
$img = new-object Drawing.Bitmap($imageName)

$adjustedImageSize = $img.Size
$ratio = [double] 1;

# Adjust image size to fit on the paper
if ($fitImageToPaper) {
$fitWidth = [bool] ($img.Size.Width > $img.Size.Height)
if (($img.Size.Width -le $_.MarginBounds.Width) -and
($img.Size.Height -le $_.MarginBounds.Height)) {
$adjustedImageSize = new-object System.Drawing.SizeF($img.Size.Width, $img.Size.Height)
} else {
if ($fitWidth) {
$ratio = [double] ($_.MarginBounds.Width / $img.Size.Width);
} else {
$ratio = [double] ($_.MarginBounds.Height / $img.Size.Height)
}

$adjustedImageSize = new-object System.Drawing.SizeF($_.MarginBounds.Width, [float]($img.Size.Height * $ratio))
}
}

# calculate destination and source sizes
$recDest = new-object Drawing.RectangleF($pageBounds.Location, $adjustedImageSize)
$recSrc = new-object Drawing.RectangleF(0, 0, $img.Width, $img.Height)

# Print to the paper
$_.Graphics.DrawImage($img, $recDest, $recSrc, [Drawing.GraphicsUnit]"Pixel")

$_.HasMorePages = $false; # nothing else to print
})

$doc.Print()
}





Oh yeah, I would appreciate it if anyone can tell me how i can format the code to fit on to the site :)

Tags :
 
Let's get lazy with PowerShell!

Name:
Location: Flushing, NY, United States

Experimenting with a different format of blogs...

Links
ARCHIVES
10/01/2005 - 11/01/2005 / 11/01/2005 - 12/01/2005 / 12/01/2005 - 01/01/2006 / 01/01/2006 - 02/01/2006 / 02/01/2006 - 03/01/2006 / 03/01/2006 - 04/01/2006 / 04/01/2006 - 05/01/2006 / 05/01/2006 - 06/01/2006 / 06/01/2006 - 07/01/2006 / 07/01/2006 - 08/01/2006 / 08/01/2006 - 09/01/2006 / 10/01/2006 - 11/01/2006 / 11/01/2006 - 12/01/2006 /


Powered by Blogger