11/29/09

PowerShell Load Assembly Function

LoadAssembly loads an assembly into the PowerShell session.

Note that unloading an assembly from PowerShell requires closing the PowerShell window, so close the window before trying to rebuild or delete a loaded assembly.
function loadAssembly($file)
{
  [system.reflection.assembly]::loadfile($file) | out-null
}

Example
loadAssembly c:\lib\file.dll

11/27/09

YUI Compressor for JavaScript and CSS

The YUI Compressor can be used to compress JavaScript and CSS files. It also offers a low-security JavaScript obfuscation option via local symbol renaming - it does not rename functions.

The tool requires the Java SDK 1.4 or later and can be run from the command line. The command line is useful because formatted, commented JavaScript can be used for development and compressed versions can be easily generated for test and prod.

To avoid compression build errors, verify your file text encoding. For Visual Studio UTF-8, make sure to select the "Unicode UTF-8 without signature" encoding from the File - Advanced Save Options menu. Then include the charset UTF-8 option in the command.

Example - run as one line
java -jar c:\lib\yui\yuicompressor-2.4.2.jar
c:\code\web\scripts\file.js
-o c:\code\web\scripts\file.min.js
--charset utf-8

11/22/09

PowerShell SharpZipLib Script

These PowerShell scripts can be used to zip and unzip files.

Zip operates on file lists such as output from the Get-ChildItem cmdlet. You can set the zip file root folder by specifying the leading folder path to remove. The Where-Object cmdlet can be used for advanced filtering. This function does not zip empty folders. See the SharpZipLib wiki for examples of zipping empty folders. Also, this function does not work with files that are locked, such as log files that are being written.

The free SharpZipLib .NET Zip assembly is used for zip functionality. You'll need to download the assembly and load it into PowerShell to run the scripts. Note that after you download or copy the assembly locally, you may have to trust the assembly. To do this, right-click the assembly and trust (unblock) it. Other related info can be found the SharpZipLib wiki.

These PowerShell scripts were tested using SharpZipLib version 0.85.5.
Strong name: ICSharpCode.SharpZipLib, Version=0.85.5.452, Culture=neutral, PublicKeyToken=1b03e6acf1164f73
function zip($zipFile, $leadingFolderPathToRemove)
{
  begin
  {
    $zip = [icSharpCode.sharpZipLib.zip.zipFile]::create($zipFile)
    $zip.beginUpdate()
  
    #add trailing backslash if necessary
    $leadingFolderPathToRemove = (join-path $leadingFolderPathToRemove '\')
  }
  process
  {
    #remove leading folder path from file name
    $file = $_.fullName.remove(0, $leadingFolderPathToRemove.length)
    $zip.add($_.fullName, $file)
  }
  end
  {
    $zip.commitUpdate()
    '{0} files zipped' -f $zip.count
    $zip.close()
  }
}

function unzip($zipFile, $unzipToFolder)
{
  $zip = new-object icSharpCode.sharpZipLib.zip.fastZip
  $zip.extractZip($zipFile, $unzipToFolder, $null)
}

Examples
loadAssembly c:\lib\sharpZipLib\ICSharpCode.SharpZipLib.dll

#zip all files from folder c:\code\web\ into c:\temp\web.zip
gci c:\code\web\* -include *.* -recurse -force | zip c:\temp\web.zip c:\code\web\

#only files modified 11-22-2009 or later
gci c:\code\web\* -include *.* -recurse -force |
where {$_.lastWriteTime -ge [dateTime]"11-22-2009 00:00"} |
zip c:\temp\web.zip c:\code\web\

#exclude files: *.csproj*, *.pdb, *.refresh, *.sln, *.suo
#exclude folders: debug, obj, release, properties
$excludeRegex = '(\.(csproj(.*)|pdb|refresh|sln|suo)$)|(\\(debug|obj|release|properties)(\\|$))'
gci c:\code\web\* -include *.* -recurse -force |
where {$_.fullName -notMatch $excludeRegex} |
zip c:\temp\web.zip c:\code\web\

#unzip c:\temp\web.zip into folder c:\temp\unzip\web\
unzip c:\temp\web.zip c:\temp\unzip\web

11/15/09

PowerShell Find Files Script

FindFiles returns a list of files that contain the search text. The search can be plain text or a regular expression.

This function is similar to using the Select-String cmdlet with the -list switch parameter. The difference is that FindFiles supports searching across line breaks. See the examples that use the "dot matches line breaks" regex pattern (?s).
function findFiles($text)
{
begin
{
$count = 0
}
process
{
$data = [system.io.file]::readAllText($_.fullname)
if ($data -match $text) #if matches at least once...
{
$_.fullname
$count += 1
}
}
end
{
"$count files found"
}
}

Examples
#find files containing "abc"
gci c:\* -include *.txt | findFiles 'abc'

#find files containing "abc" or "xyz"
gci c:\* -include *.txt | findFiles 'abc|xyz'

#find files containing "abc", including across line breaks
gci c:\* -include *.txt | findFiles '(?s)a.*bc|ab.*c'

#find files containing "<abc>" tags, including across line breaks, and empty tags
gci c:\* -include *.txt | findfiles '(?s)<abc>.*</abc>|<abc/>'

8/19/09

Hash Functions

GetHash returns the hash value of a byte array.
GetHashStr returns the hash value of a string.

These functions can use any of the hash classes from the System.Security.Cryptography namespace, e.g. MD5, SHA1, SHA256, SHA512.
//C#
using System;
using System.Security.Cryptography;
using System.Text;

namespace ExpressionSoftware.Security.Crypt
{
    public static class Hash
    {
        public static byte[] GetHash(byte[] bs, Type hashType)
        {
            return HashAlgorithm.Create(hashType.Name).ComputeHash(bs);
        }
        
        public static byte[] GetHashStr(string input, Type hashType)
        {
            byte[] bs = Encoding.UTF8.GetBytes(input);
            return GetHash(bs, hashType);
        }
    }
}

//F# v1.9.7.8
namespace ExpressionSoftware.Security.Crypt
open System
open System.Security.Cryptography
open System.Text

module Hash =
  let GetHash(bs:byte[], hashType:Type) =
    HashAlgorithm.Create(hashType.Name).ComputeHash bs

  let GetHashStr(input:string, hashType:Type) =
    Encoding.UTF8.GetBytes input
    |> (fun bs -> GetHash(bs, hashType))

#PowerShell
function getHash($bs, $hashType)
{
  $hashType::create().computeHash($bs)
}

function getHashStr($inputStr, $hashType)
{
  getHash ([system.text.encoding]::utf8.getBytes($inputStr)) $hashType
}

Examples
//C#
byte[] bs = Encoding.UTF8.GetBytes("foo");
byte[] hash = Hash.GetHash(bs, typeof(SHA1));
Debug.WriteLine(Byte.BytesToString(hash, "{0} "));
11 238 199 181 234 63 15 219 201 93 13 212 127 60 91 194 117 218 138 51  //output

//F#
let hash = Hash.GetHashStr("foo", typeof<SHA1>)
Byte.BytesToString(hash, "{0:x} ")
|> (fun s -> printfn "%s" s)
b ee c7 b5 ea 3f f db c9 5d d d4 7f 3c 5b c2 75 da 8a 33  //output

#PowerShell
$hashType = [system.security.cryptography.SHA1]
$hash = getHashStr 'foo' $hashType
bytesToString $hash '{0:X}'
BEEC7B5EA3FFDBC95DDD47F3C5BC275DA8A33  #output

8/18/09

Bytes to String Function

BytesToString returns a byte array as a formatted string.

02-05-10 This function has been replaced with a generic version - Generic Array to String Function.
//C#
using System.Text;

namespace ExpressionSoftware.System
{
    public static class Byte
    {
        public static string BytesToString(byte[] bs, string format)
        {
            var sb = new StringBuilder(bs.Length * 4);
            foreach (byte b in bs)
            {
                sb.AppendFormat(format, b);
            }
            return sb.ToString();
        }
    }
}

//F# v1.9.7.8
namespace ExpressionSoftware.System
open System.Text

module Byte =
  let BytesToString(bs:byte[], format:string) =
    let sb = new StringBuilder(bs.Length * 4)
    bs |> Array.iter(fun b -> sb.AppendFormat(format, b) |> ignore)
    sb.ToString()

#PowerShell
function bytesToString($bs, $format)
{
  $bs | %{$result += ($format -f $_)}
  $result
}

Examples
//C#
byte[] bs = { 102, 111, 111 };
Debug.WriteLine(Byte.BytesToString(bs, "{0}"));  //default format
102111111  //output

//F#
let bs = [|102uy; 111uy; 111uy|]
Byte.BytesToString(bs, "{0:d4}-")  //4 digit width format
|> (fun s -> printfn "%s" s)
0102-0111-0111-  //output

#PowerShell
[byte[]]$bs = 102,111,111
bytesToString $bs '{0:x} ' #hex format
66 6f 6f  #output

8/14/09

Listing Users From the Windows Event Log

GetEventLogUsers returns a list of users from the Windows EventLogs, e.g. Application, Security, System. This function returns the entire dataset, unsorted. See examples for sorting and returning distinct lists.

Note: This function works on Windows XP, but not Window Server 2008.
//C#
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace ExpressionSoftware.EventLogs
{
    public static class EventLogQuery
    {
        public static IEnumerable GetEventLogUsers(string logName)
        {
            EventLog log = new EventLog(logName);
            var users = from e in log.Entries.Cast()
                        select e.UserName;
            return users;
        }
    }
}

//F# v1.9.7.8
namespace ExpressionSoftware.EventLogs
open System.Diagnostics

module EventLogQuery =
  let GetEventLogUsers logName =
    let log = new EventLog(logName)
    log.Entries
    |> Seq.cast
    |> Seq.map (fun x -> x.UserName)

#PowerShell
function getEventLogUsers($logName)
{
  $log = new-object system.diagnostics.eventLog($logName)
  $log.entries | %{$_.username}
}

Examples
//C#
var users = EventLogQuery.GetEventLogUsers("security");
users = users.Distinct().OrderBy(u => u);
foreach (string user in users)
{
    Debug.WriteLine(user);
}

//F#
let users = EventLogQuery.GetEventLogUsers "security" |> Seq.distinct |> Seq.sort
for user in users do
  printfn "%s" user

#PowerShell
getEventLogUsers 'security' | sort-object | get-unique

Output
DEV\john
NT AUTHORITY\ANONYMOUS LOGON
NT AUTHORITY\LOCAL SERVICE
NT AUTHORITY\NETWORK SERVICE
NT AUTHORITY\SYSTEM

5/30/09

PowerShell Hash Scripts for File Comparisons

See the Windows PowerShell Cookbook recipe 17.10 "Get the MD5 or SHA1 Hash of a File", for original script.

GetFileHash returns the hash value for a file. The hash type can be any hash class from the System.Security.Cryptography namespace, e.g. MD5, SHA1, SHA256, SHA512.
CompareFileHash returns true if the files have the same hash.
CompareFileHashInfo returns the hash comparison information.
GetFileHashObject returns a file hash wrapper object.
function getFileHash($file, $hashType)
{
$stream = new-object io.streamReader $file
$hash = $hashType::create().computeHash($stream.baseStream)
$stream.close()
trap
{
if ($stream -ne $null)
{
$stream.close()
}
break
}
[string] $hash
}

function compareFileHash($file1, $file2, $hashType)
{
(getFileHash $file1 $hashType) -eq (getFileHash $file2 $hashType)
}

function compareFileHashInfo($file1, $file2, $hashType)
{
$f1 = getFileHashObject $file1 $hashType
$f2 = getFileHashObject $file2 $hashType

$f1
$f2
"Hash Type: " + $hashType.name
"Duplicate Files: " + ($f1.hash -eq $f2.hash)
}

function getFileHashObject($file, $hashType)
{
$fileHash = new-object psObject
$fileHash | add-member noteProperty file $file
$fileHash | add-Member noteProperty hash (getFileHash $file $hashType)
return $fileHash
}

Examples
>> $hashType = [system.security.cryptography.MD5]
>> getFileHash c:\file1.txt $hashType
52 85 168 127 81 223 163 157 187 191 244 34 221 99 48 201

>> compareFileHash c:\file1.txt c:\file2.txt $hashType
False

>> compareFileHashInfo c:\file1.txt c:\file2.txt $hashType | fl
file : c:\file1.txt
hash : 52 85 168 127 81 223 163 157 187 191 244 34 221 99 48 201

file : c:\file2.txt
hash : 100 221 101 253 63 62 26 193 155 80 181 198 78 247 255 196

Hash Type: MD5
Duplicate Files: False