Monday, 25 October 2021

Keep alive

function keepalive(){
	$wsh = New-Object  -ComObject wscript.shell
	$i = 0
	$interval = 200
	while($true){
		Write-Host "`t$i" -NoNewline 
		$i = $i + $interval
		sleep -Seconds $interval
		$wsh.SendKeys("{F14}")
	}
}

Tuesday, 9 September 2014

Wednesday, 20 February 2013

Passing an array to invoke-command

When passing an array to invoke-command to be used on a remove machine, the PARAM will only read the first entry if passed as below:

$ar = @("a","b","c")
invoke-command -ArgumentList $ar -ComputerName mypc1 -ScriptBlock {param($opts);write-host $opts;write-host $opts.length}


Result:
a
1

To read in the array correctly, use the syntax (,$myArray)

$ar = @("a","b","c")
invoke-command -ArgumentList (,$ar) -ComputerName mypc1 -ScriptBlock {param($opts);write-host $opts;write-host $opts.count}


Result:
a b c
3

Monday, 22 October 2012

Ternary Operator support in Powershell

It's always bugged me that Powershell had no support for Ternary Operators as with C# or Java/JavaScript.

e.g.:
var a = (b == 1)?true:false;


Fortunately, there is a way however it doesn't use the usual ?: notation:


$a = 4
@{$true=1;$false=0}[$a -lt 5]  


It's also possible to call a function from within the query:

function retValue($ret){
    return " "+$ret
}
$b = 0
$a = @{$true=retValue "FOO!";$false=retValue "BAR!"}[$b -eq 1]

Tuesday, 9 October 2012

Creating a Powershell Module in C#

I'd like to take the SHA1Crypt powershell script I posted yesterday and create a C# module - it was a lot easier than I thought:

  1. Create the usual windows class Library Project
  2. Change the project to .NET Framework 3.5. If you leave as .NET 4, you will need to force powershell to start using .NET4 (default is 2.0.5 viewed with [environment]::Version)
  3. Add following references:
    •     System.Management
    •     System.Security
    •     System.Management.Automation - Download Powershell 2.0 SDK (PowerShellV2_SDK_Samples.msi) from http://www.microsoft.com/en-us/download/details.aspx?id=2560
  4. Remove the default public class Class1
  5. Create your classes as below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace SHA1Crypt
{
    [System.Management.Automation.Cmdlet(System.Management.Automation.VerbsCommon.Get, "Encrypted")]
    public class Encrypt : System.Management.Automation.PSCmdlet
    {
        [System.Management.Automation.Parameter(Position = 0, Mandatory = true, HelpMessage = "String to be encrypted")]
        public string PlainString;
        [System.Management.Automation.Parameter(Position = 1, Mandatory = true, HelpMessage = "Pass Key should be the same as used to encrypt if decrypting")]
        public string passKey;

        protected override void ProcessRecord()
        {
            byte[] Results;
            System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();

            TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();

            SHA1CryptoServiceProvider HashProvider = new SHA1CryptoServiceProvider();
            byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(passKey));
            byte[] key = new byte[24];
            TDESKey.CopyTo(key, 0);
            TDESAlgorithm.Key = key;
            
            TDESAlgorithm.Mode = CipherMode.ECB;
            TDESAlgorithm.Padding = PaddingMode.PKCS7;

            byte[] DataToEncrypt = UTF8.GetBytes(PlainString);

            try
            {
                ICryptoTransform Encryptor = TDESAlgorithm.CreateEncryptor();
                Results = Encryptor.TransformFinalBlock(DataToEncrypt, 0, DataToEncrypt.Length);
            }
            finally
            {
                TDESAlgorithm.Clear();
                HashProvider.Clear();
            }

            this.WriteObject(Convert.ToBase64String(Results), true);
        }
    }

    [System.Management.Automation.Cmdlet(System.Management.Automation.VerbsCommon.Get, "Decrypted")]
    public class Decrypt : System.Management.Automation.PSCmdlet
    {
        [System.Management.Automation.Parameter(Position = 0, Mandatory = true, HelpMessage = "Encrypted string to be decrypted")]
        public string EncryptedString;
        [System.Management.Automation.Parameter(Position = 1, Mandatory = true, HelpMessage = "Pass Key should be the same as used to encrypt if decrypting")]
        public string passKey;

        protected override void ProcessRecord()
        {
            byte[] Results;
            System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();

            TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();

            SHA1CryptoServiceProvider HashProvider = new SHA1CryptoServiceProvider();
            byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(passKey));
            byte[] key = new byte[24];
            TDESKey.CopyTo(key, 0);
            TDESAlgorithm.Key = key;

            TDESAlgorithm.Mode = CipherMode.ECB;
            TDESAlgorithm.Padding = PaddingMode.PKCS7;

            byte[] DataToDecrypt = Convert.FromBase64String(EncryptedString);

            try
            {
                ICryptoTransform Decryptor = TDESAlgorithm.CreateDecryptor();
                Results = Decryptor.TransformFinalBlock(DataToDecrypt, 0, DataToDecrypt.Length);
            }
            finally
            {
                TDESAlgorithm.Clear();
                HashProvider.Clear();
            }

            this.WriteObject(UTF8.GetString(Results), true);
        }
    }
}


Import the module in the usual way:
Import-Module .\SHA1Crypt.dll
Get-Module

ModuleType Name                      ExportedCommands
---------- ----                      ----------------
Binary     SHA1Crypt                 {Get-Decrypted, Get-Encrypted}

Get-Encrypted -PlainString woohoo -passKey thisismykey
xhWWiEyQDhs=

Get-Decrypted -EncryptedString xhWWiEyQDhs= -passKey thisismykey
woohoo



As an alternative to passing the passKey as a parameter, if it's not likely to change, add it to your module as bytes (NB a string can be viewed by opening the dll in Notepad!! Bytes are more tricky to work out ;) )

Nice advantage is you can reuse the exact same code + key in an ASP.NET page for administrative purposes.

Monday, 8 October 2012

Use SHA1 Crypto provider to create a Hash of a pass key to tripledes encrypt/decrypt a string:

param(
 [parameter(Mandatory = $true, HelpMessage = "Action type: e.g. Encrypt(E)/Decrypt(D)")] [string] $Action,
 [parameter(Mandatory = $true, HelpMessage = "Pass Key should be the same as used to encrypt if decrypting")] [string] $passKey,
 [parameter(Mandatory = $true, HelpMessage = "String to be encrypted or decrypted")] [string] $message
)

 [System.Reflection.Assembly]::LoadWithPartialName('System.Security.Cryptography')
 [System.Reflection.Assembly]::LoadWithPartialName('System.Collections.Generic')
 [System.Reflection.Assembly]::LoadWithPartialName('System.Text')

 $HashProvider = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider
 $TDESAlgorithm = New-Object System.Security.Cryptography.TripleDESCryptoServiceProvider

 [Byte[]] $TDESKey = $HashProvider.ComputeHash([System.Text.UTF8Encoding]::UTF8.GetBytes($passKey));
 $keyByte = New-Object byte[] 24
 $TDESKey.CopyTo($keyByte, 0);

 $TDESAlgorithm.Key = $keyByte
 $TDESAlgorithm.Mode = [System.Security.Cryptography.CipherMode]::ECB
 $TDESAlgorithm.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7

 switch -regex ($Action.toLower()){
  "d(ecrypt)?"{
   try{
    [Byte[]] $DataToDecrypt = [convert]::FromBase64String($Message)
    $Decryptor = $TDESAlgorithm.CreateDecryptor()
    $Results = $Decryptor.TransformFinalBlock($DataToDecrypt, 0, $DataToDecrypt.Length)
   }finally{
    $TDESAlgorithm.Clear()
    $HashProvider.Clear()
   }
   return [System.Text.UTF8Encoding]::UTF8.GetString($Results)
  }
  "e(ncrypt)?"{
   [Byte[]] $DataToEncrypt = [System.Text.UTF8Encoding]::UTF8.GetBytes($Message)
   try{
    $Encryptor = $TDESAlgorithm.CreateEncryptor();
    $Results = $Encryptor.TransformFinalBlock($DataToEncrypt, 0, $DataToEncrypt.Length);
   }finally{
    $TDESAlgorithm.Clear();
    $HashProvider.Clear();
   }
   return [Convert]::ToBase64String($Results)
  }
 }


<#
.SYNOPSIS
Encrypt or Decrypt strings with a pass key

.DESCRIPTION
Uses SHA1 Crypto provider to create a Hash of a pass key to tripledes encrypt/decrypt a string

EDIT HISTORY:                                                        
08/10/2012 v1.0 Initial Release

.PARAMETER Action
Choose to Encrypt (E) or Decrypt (D)

.PARAMETER passKey
Pass key to be used to encrypt or decrypt a string

.PARAMETER message
String to be encrypted or decrypted

.INPUTS
None.

.OUTPUTS
Returns string

.EXAMPLE
PS > .\SHA1Crypt.ps1 -Action e -message testmessage -passKey thisismykey1

.EXAMPLE
PS > .\SHA1Crypt.ps1 -Action Decrypt -message "IZTkBEuz6JbWvBlNQaN2wA==" -passKey thisismykey1

#>

Monday, 24 September 2012

Found some useful code to assist with embedding images as Base64. Outputs element style tag as well as image element:
function retBase64Image($path){
 $newImg = [convert]::ToBase64String((get-content $path -encoding byte))
 $ext = gci $path | select @{Name="Ext";Expression={$_.Extension.substring(1)}} | select -ExpandProperty Ext
 Write-Host "style='background:url(data:image/$ext;base64,$newImg) right bottom no-repeat'"
 Write-Host "<img src='data:image/$ext;base64,$newImg' />"
}

retBase64Image -path "C:\MyImages\Image1.gif"