Archive for November, 2008

Making Windows PowerShell a great place to work

To get started with PowerShell you will of course need to download and install Windows PowerShell if you don’t have it already. Then I recommend installing a visual editor such as PowerGUI which includes a powerful script editor that includes intellisense for PowerShell.

PowerShell is definitely a very powerful scripting environment, but I couldn’t help but find myself a little frustrated at some small shortcomings in it’s out of the box use. The main problem I have is it isn’t simple to use custom commands or functions from your PowerShell environment from anywhere, at any time. What I really wanted to do was build up a library of functions that I could use in my day to day life with PowerShell that take all the manual labour out of some very simple tasks. I wanted this customisation to be extremely simple too, and here’s what I came up with:

Making PowerShell load your Scripts Library every time

  • Start –> All Programs –> Windows PowerShell * Right Click –> Run As Administrator
  • Type: Set-ExecutionPolicy RemoteSigned
  • Start –> All Programs –> PowerGUI
  • Select File –> Open Current User Profile –> Microsoft.Powershell_profile.ps1
  • Insert the following code:
$profileFolder = Get-Item Env:USERPROFILE
$scriptsFolder = $profileFolder.Value + "\Documents\WindowsPowerShell"
$scriptFiles = Get-ChildItem $scriptsFolder -Include "*.ps1" -Recurse -Exclude "*_profile.ps1"
foreach ($scriptFile in $scriptFiles)
{
    Write-Host Loading library script $scriptFile
    . $scriptFile
}

  • Save the file.

Now every time Windows PowerShell starts, it will load all *.ps1 files found in your Documents\WindowsPowerShell folder (except for the *_profile.ps1 you are editing). Now you can build up a library of Script files that declare useful functions for you to work with:

Adding to your Scripts Library

I’ll now give you an example of a handy function I think should be part of my PowerShell environment, it’s called Set-FileCreated (You should always name your functions in the Verb-Noun format). Set-FileCreated simply updates the created, last modified and last accessed times to whatever time you specify (or the current time if not specified)

  • Use your favourite text editor to create a new text file called Set-FileCreated.ps1. The name of the file actually has no bearing on the function you’ll be declaring but it’s a good practice for maintenance purposes to have one function per file, with the file named the same as the function.
  • Add the following text to the file:
Function Set-FileCreated
{
    Param
    (
        [string]$Path=$(Throw "You must specify the name of a file"),
        [datetime]$Touch=(Get-Date)
    ) 
  
     [datetime]$UTCTime=$Touch.ToUniversalTime()
     
     $file=Get-Item $Path -ea "silentlycontinue"
     if ($file) 
     {
         Write-Host "Touching $path" -foregroundcolor Green
         $file.CreationTime=$Touch
         $file.CreationTimeUtc=$UTCTime
         $file.LastAccessTime=$Touch
         $file.LastAccessTimeUtc=$UTCTime
         $file.LastWriteTime=$Touch
         $file.LastWriteTimeUtc=$UTCTime
     }
     else 
     {
         Write-Warning "Failed to find $path"
     }
 }
  • Now save the file under Documents\WindowsPowerShell\Set-FileCreated.ps1
  • Run PowerShell, Start –> All Programs –> Windows PowerShell (run as administrator not necessary)
  • Now the function will be loaded from the Set-FileCreated.ps1 script and you can run it from anywhere by typing: Set-FileCreated myfile.txt

As I gather useful script functions I’ll be posting them online on my SkyDrive (link below) for anyone to copy into their scripts library folder.

**UPDATE** I’ve changed this from Touch-File to Set-FileCreated to conform to PowerShell’s verb naming convention.

http://cid-17124d03a9a052b0.skydrive.live.com/embedrowdetail.aspx/Public/PowerShell

Thanks to Lee Holmes for the Add-OutlookTask script

Have fun!

Advertisements

1 Comment

Fixing CryptographicException “Object Already Exists”

I’ve got a couple of ASP.NET web sites running on the same machine that need to share access to a Key Container used for encrypting and decrypting authentication tickets.

Sample code for the encryption:

/// <summary>
/// Encrypt using RSA
/// </summary>
/// <param name="dataToEncrypt"></param>
/// <param name="keyContainerName"></param>
/// <returns></returns>
/// <exception cref="T:System.Security.Cryptography.CryptographicException"/>
internal static byte[] RSAEncrypt(byte[] dataToEncrypt, string keyContainerName)
{
    if (dataToEncrypt == null || dataToEncrypt.Length == 0)
        return null;

    try
    {
        CspParameters cspParams = new CspParameters();
        cspParams.Flags = CspProviderFlags.UseMachineKeyStore;
        cspParams.KeyContainerName = keyContainerName;
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cspParams);
        List<byte> allData = new List<byte>();
        for (int i = 0; i < dataToEncrypt.Length; i += RsaBlockSize)
        {
            allData.AddRange(
rsa.Encrypt(dataToEncrypt.Skip(i).Take(RsaBlockSize).ToArray(),
DoOAEPPadding)); } return allData.ToArray(); } catch (CryptographicException) { // TODO: Log the encryption error throw; } }

This was encrypting and decrypting fine in the first web site, but the second web site was throwing a CryptographicException “Object Already Exists” when attempting to decrypt the information.  After some research it seems this is a security exception to do with access to the key container (basically the ASP.NET user account could tell there was a key container but did not have access to use it for decryption, so was throwing an “Object Already Exists” exception).

This can be fixed with the following command line:

aspnet_regiis -pa "SampleKeys" "NT AUTHORITY\NETWORK SERVICE"

Where “SampleKeys” is the Key Container name. Here is some documentation on the subject from the MSDN website.

3 Comments