Category Archives: WindowsPowershell

TimeSpan Conversion Function and Module

I have a ton of Powershell code I’ve written over the last 6 years or so that I’m in the process of cleaning up and looking to share.  I plan on re-presenting them as a set of scripts and script modules I’ll be featuring in a series of blog posts coming in the near future.

I’ll start simply.  I have a new script module called bsti.conversion that has a single function:  ConvertTo-TimeSpan

I always thought it was neat that you could type in 1kb and Powershell would convert that value to 1024.  You can also use mb (megabytes), tb (terabytes), and pb (petabytes).  I don’t see that eb (exabytes) works.  In any case, I always wished I could do the same with time units like this:

12m (minutes) or 24h (hours) or 7d (days)

The ConvertTo-TimeSpan function I’ve included in this module does just that.

What I use this for is I have functions and scripts I like to write that require the user to pass in an easy time unit value.

This functionality can also be achieved by Timespan conversion like so:

[Timespan](“1.00:00:00”)  # 1 day
[Timespan](“1.6:00:00”)  # 1 day, 6 hours
[Timespan](“1:22:00”)  # 1 hour, 22 minutes

The conversion function is a little less precise, but a bit more human-readable, which is important to me since most of my users are not .NET programmers and don’t understand the format of a timespan object right offhand.

The function in this module supports both formats:

bsti.conversion1

The module files can be downloaded here.
Once downloaded, extract the folder to the C:\windows\system32\windowspowershell\v1.0\modules directory.  The final structure should look like this:
C:\windows\system32\windowspowershell\v1.0\modules\bsti.conversion

Then just use the Import-Module bsti.conversion command as shown above.

Not bad for a start, hope you enjoy.

UPDATE:  I’m adding my stuff to GitHub.  Bear with me while I come up-to-speed on how to use it.  Find this module project here:

https://github.com/Roadkill4545/bsti.Powershell/tree/master/bsti.conversion

Automatically Transcripting all Powershell Sessions

If you love Windows Powershell as much as I do, you probably find yourself using it to complete day-to-day management tasks in addition to scripting and automation.

More and more hardware vendors, like NetApp and VmWare, provide very robust Powershell toolsets.  Because I’m such a command line guy, and these Powershell libraries are so powerful, I perform nearly all of my management tasks from Powershell.  I find tasks like provisioning and destroying storage, creating clones, managing snapshots, and getting data from virtual machines much easier via the command line in many cases.

Because this is a day-to-day thing to me, it’s useful to have all of the code I type in and the output I get back automatically logged to a file for future perusal.  I liken it to the administrators who manage a lot via SSH, and setup Putty to log all sessions to a file.  This allows me to look at past actions, remember how I did stuff, or see what I did wrong if something got messed up.  It can also helpful for auditing if you need to track who did what using Powershell.

Below is a procedure I use on all management stations I use Powershell from.  This procedure automatically logs all activity from the command line to a file.

By default, it creates a new transcript file in the C:\users\myusername\LogFiles\Powershell\computername directory.

You can override this if you want to go to a central location, by calling the Set-TranscriptFilePath function.

For instance, to transcript everything to a central file share:

Set-TranscriptFilePath -path "\\myserver\LogFiles\Powershell\server1"

It creates one new transcript file per session you launch, so you won’t have multiple sessions writing over the same file.

To set this up, create a new file called profile.ps1 in one of the following directories:

Apply to just the current user:
C:\users\myusername\documents\WindowsPowershell\profile.ps1   only

Or to apply to all users on the computer:
c:\windows\system32\WindowsPowershell\v1.0\profile.ps1

Copy the following script text to the profile script you created:

<# 
  .SYNOPSIS 
  Windows Powershell console profile script. This script is generic enough to be run from any machine. It sets up console logging to a network share for servers and locally for workstations. 
  NOTE: This will not transcript in Powershell ISE! Transcripting in ISE is supported in the current (early) version of Windows Management Framework 5.0 however. 
#>

$script:TranscriptFileKey = "HKLM:\SOFTWARE\PowershellManagement\Powershell"

#############################################################################################################################################
# FUNCTIONS
#############################################################################################################################################

function Get-TranscriptFilePath()
{
  <# 
    .SYNOPSIS 
    This function returns the location where Powershell session transcript log files go. 
  #>

  [CmdletBinding()]
  param
  (
  )

  $transcriptFilePath = ""

  # User can override log path in registry:
  if ( Test-Path -Path $script:TranscriptFileKey )
  {
    $regKey = Get-Item -Path $script:TranscriptFileKey
    if ( $regKey.Property -icontains "RootTranscriptPath" )
    {
      $transcriptFilePath = (Get-ItemProperty -Path $script:TranscriptFileKey -Name "RootTranscriptPath").RootTranscriptPath
    }
  }

  if ( !$transcriptFilePath )
  {
    # Station is a workstation, use local path:
    $transcriptFilePath = Join-Path $Env:USERPROFILE -ChildPath "LogFiles\Powershell\$($Env:ComputerName)"
  }

  # Create the log file path if it does not exist:
  if ( !(Test-Path -Path $transcriptFilePath) )
  {
    New-Item -ItemType directory -Path $transcriptFilePath -Force | Out-Null
  }

  $transcriptFilePath
}

function New-TranscriptFilePath()
{
  Join-Path -Path (Get-TranscriptFilePath) -ChildPath ("Powershell {0:MM dd yyyy hh mm ss} {1:00000}.log" -f (Get-Date),$PID)
}

function Test-Administrator
{
  $user = [Security.Principal.WindowsIdentity]::GetCurrent()
  (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}

function Set-TranscriptFilePath()
{
  <# 
    .SYNOPSIS 
    This function sets the transcript file path from the default. This affects all future Powershell sessions. 
    
    .PARAMETER Path 
    Specifies the new path where future transcript files get saved to. This will remain the path until it is changed. Set this to "" to reset to the default path: C:\users\username\LogFiles\Powershell\computername 
  #>

  [CmdletBinding(SupportsShouldProcess=$true)]
  param
  (
    [string] $Path
  )

  if ( !(Test-Administrator) )
  {
    throw ("You must launch this console as an administrator to execute this function!")
  }

  if ( $Path )
  {
    if ( !(Test-Path -Path $Path) )
    {
      # Create the registry path:
      New-Item -ItemType Directory -Path $script:TranscriptFileKey -Force -ErrorAction Stop | Out-Null
    }
  }

  Set-ItemProperty -Path $script:TranscriptFileKey -Name RootTranscriptPath -Value $Path -ErrorAction Stop | Out-Null

  if ( !$Path )
  {
    $Path = Join-Path $Env:USERPROFILE -ChildPath "LogFiles\Powershell\$($Env:ComputerName)"
  }

  Write-Host ("Future transcript files will be saved to the following directory: $Path") -ForegroundColor Green
}

Once complete, every new Powershell console session you launch will be automatically transcripted!

Note: As of Powershell 4.0, you can’t transcript from the Powershell session that gets launched from Powershell ISE.  This is due to a difference in the console.  However, I have noticed it works OK in the preview of Windows Management Framework 5.0, so i suspect support for this is coming soon.

I’ve uploaded the script here if you’d rather not cut-and-paste.