What’s in Your PowerShell Profile? Microsoft PFEs' Favorites

What’s in Your PowerShell Profile? Microsoft PFEs' Favorites

  • Comments 5
  • Likes

Summary: Microsoft premier field engineers share some of their favorite functions from their Windows PowerShell profiles.

Microsoft Scripting Guy, Ed Wilson, is here. Today we will look at some profile excerpts from a few Microsoft premier field engineers (PFEs).

Michael Wiley offers the following idea:

"I actually got this from Ashley McGlone, but I use it extensively for giving presentations and demos. My $Profile for ISE contains the following lines to make error text more readable on projectors and to increase the font size."

# Make error text easier to read in the console pane.

$psISE.Options.ErrorBackgroundColor = "red"

$psISE.Options.ErrorForegroundColor = "white"


# Make text easier to read at larger resolutions

$psISE.Options.Zoom = 125

"And I use the following for the $Profile in console."

$a = (Get-Host).PrivateData

$a.ErrorBackgroundColor = "red"

$a.ErrorForegroundColor = "white"

"I adjust the font setting on my console to 18pt Lucinda Console, and the Layout is 80 wide by 35 high. I also apply these same settings inside all of my virtual machines. On a typical 1024x768 projector, this makes the text very readable for students."

Ashley McGlone (@GoateePFE) provided this additional tip:

"As part of my work, I teach many Windows PowerShell workshops for our customers. I’ve been using Windows PowerShell for four years, and I run a fairly minimal profile for both the console and the ISE. I do this for two reasons:

1. I am a purist, and I like things clean and simple.

2. I want to have a default environment when I am teaching students.

"Here is what I use in my console profile."

# Clean out small files from my transcript folder

dir C:\Users\asmcglon\Documents\PowerShell\_Transcripts\*.txt | ? length -lt 1kb | remove-item

# Log a transcript for every console session in case I need to go back and find a command later

Start-Transcript -Path "C:\Users\ashley\Documents\PowerShell\_Transcripts\$(Get-Date -Format yyyyMMddHHmmss).txt" | Out-Null

# Set the console error colors to white text on red background.

# This is much easier to read on a projector.

$a = (Get-Host).PrivateData

$a.ErrorBackgroundColor = "red"

$a.ErrorForegroundColor = "white"

"Here is what I use in my ISE profile."

# Make error text easier to read in the console pane.

$psISE.Options.ErrorBackgroundColor = "red"

$psISE.Options.ErrorForegroundColor = "white"

# Make text easier to read at larger resolutions

$psISE.Options.Zoom = 125

"That’s it. These very basic settings help me as I teach Windows PowerShell."

Funtrol Ready says his main areas of focus are SharePoint and Windows PowerShell.

"I use a really basic profile that connects me to Office 365 where I can manage, demo, or troubleshoot the suite of products by using Windows PowerShell.

"In my ISE profile, first I capture my credentials and then connect to Office 365. This requires the installation of the Microsoft Online Services Sign-in Assistant and the Windows Azure Active Directory Module for Windows PowerShell. If I am using Windows PowerShell 2.0, I must import the module. Windows PowerShell 3.0 or later will automatically load them for me."

$o365cred = get-credential -UserName admin@<my-tenant>.onmicrosoft.com -Message cloudO365demo

Connect-MsolService -Credential $o365cred

"Next I connect to SharePoint Online. This requires downloading the SharePoint Online Management Shell."

connect-sposervice -url https://<my-tenant>-admin.sharepoint.com -Credential $o365cred

 "Next I connect to Lync Online. This requires the installation of the Lync Online Connector Module."

Import-Module LyncOnlineConnector

$session = New-CsOnlineSession -Credential $o365cred

Import-PSSession $session

"And finally, I connect to Exchange Online by using a remote session."

$exchangeSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Credential $o365cred -Authentication "Basic" -AllowRedirection

Import-PSSession $exchangeSession

Georges Maheu says that he uses Windows PowerShell every day. Most of the time, he uses Windows PowerShell with scripts, but he uses the console to test things and to do research. Here are some of the functions from his profile.

"My first function loads my profile to facilitate editions. This is very useful when you are creating your profile. The second function pipes Help text to More, which reduces scrolling. The third function lists WMI classes (excluding CIM classes). The last function is my favorite, it overwrites the default Prompt function. This provides the following:

1. Displays a timestamp to gauge timespans between commands. I use Measure-Command for more precise timing, but this provides me with a rough order of magnitude.

2. Displays the current path on its own line, which provides more real estate to type commands.

3. The green color and ‘---‘ line provides a visual clue that separates commands."


function profile  


notepad $profile

} #function profile



function moreHelp($what)


get-help -name $what -full | more

} #function moreHelp



function getWMI($what)


get-wmiobject -list |

  where-object {$_.name -match $what -and

         $_.name -notmatch "CIM_"}

} #function getWMI



function prompt()


Write-Host -ForegroundColor Green @"

PS $(get-date) $(Get-Location)




$(if ($nestedpromptlevel -ge 1) { '>>' }) + '> '

} #function prompt()


# Initialise PowerShell =======================================


(get-host).UI.RawUI.windowTitle = "George's PowerShell"

Ian Farr claims to be a PowerShell addict…

"There, I’ve said it! I also teach Windows PowerShell and help my customers with their scripts. I’ve got a lot in my $profile. Here’s some of the publishable stuff.

"I check to see whether the console has been started with ‘Run as Administrator.’ If it has, I give it a different color than that of my standard console, so I instantly know what context I’m in. I also kick off a background update of my Help files because this can only be achieved with admin permissions."

#Check for admin privs

If (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`

   [Security.Principal.WindowsBuiltInRole] "Administrator"))



  #Change the console display

  $UI = (Get-Host).UI.RawUI

  $UI.BackgroundColor = "blue"

  $UI.ForegroundColor = "white"

  $UI.WindowTitle = "Ian's Admin PowerShell"

  Set-Location c:\



  #Update Help files

  Start-Job -ScriptBlock {Update-Help -Force}




  #Change the console display

  $UI = (Get-Host).UI.RawUI

  $Size = $UI.WindowSize

    $Size.Width = 120

    $Size.Height = 60

  $UI.WindowSize = $Size

  $UI.BackgroundColor = "black"

  $UI.ForegroundColor = "darkgreen"

  $UI.WindowTitle = "Ian's PowerShell"



"The following function automatically adds -AutoSize for when I use Format-Wide or Format-Table. (I should add more of these $PsDefaultParameterValues statements because they’re awesome!)"

#Set Autosize switch for both Format-Table and Format-Wide cmdlet

$PSDefaultParameterValues['Format-[wt]*:Autosize'] = $True

Rene Mau likes to use Notepad and the console to write scripts.

"When I need information about a class or object, I’m reading the MSDN library. So the most useful profile function for me is the following. I add a ScriptMethod QuerymsdnClassInfo() to every object in the session. This method will open the MSDN website for extended information for the class."

$ProfilePath = Split-Path -Path $PROFILE –Parent
$TypesFile = Join-Path -Path $ProfilePath -ChildPath MyTypes.ps1xml

            Update-TypeData -Path $TypesFile -EA Stop
catch [System.Management.Automation.ItemNotFoundException]
            Write-Host "Update TypeData failed. Could not find $TypesFile" -ForegroundColor DarkRed
            Write-Host "Update TypeData failed. Please check syntax of $TypesFile" -ForegroundColor DarkRed








   $type = $this.GetType().FullName

   switch -Wildcard ($type)


   "System.Management.ManagementObject" { $urilist = "http://msdn.microsoft.com/en-us/library/windows/desktop/aa394554`(v=vs.85`).aspx" }

   "System.__ComObject" { $urilist = "http://www.microsoft.com/com/default.mspx" }

   default { $urilist = "http://msdn.microsoft.com/$PSUICulture/library/$type.aspx" }


   foreach ($uri in $urilist)


   If (-not $($global:iemsdn.Type) -eq "HTML Document")


    $global:iemsdn = new-object -comobject InternetExplorer.Application -property @{navigate2 = $uri; visible = $true}












Stefan Stranger specializes in System Center Operations Manager and Windows PowerShell.

"I love to use Windows PowerShell to automate and inspect systems I am working on. During the many Windows PowerShell workshops that I deliver, I’ve added more in my profile. That’s why I’ve added information about what is in my profile when I start my different Windows PowerShell hosts. In my console profile, I have the following functions."

Write-Host "Loaded in profile: Measure-Script, Scripts drive" -ForegroundColor Yellow

Write-Host "Loaded in profile: PSReadLine" -ForegroundColor Yellow

Write-Host "PSReadline example: Get-Process –<Ctrl+Space> or Get-Process i <Ctrl+Space>" -ForegroundColor Yellow

# Load Module PSProfile Module

# More info http://www.powershellmagazine.com/2013/05/13/measuring-powershell-scripts/

import-module PSProfiler


#Go to default Script folder

Set-Location C:\Scripts\PS


#Create FileSystem Drive for Script folder

New-PSDrive -Name Scripts -PSProvider FileSystem -Root C:\Scripts\PS | Out-Null


# Load Module PSReadLine Module

# More info https://github.com/lzybkr/PSReadLine

import-module PSReadLine


"In my ISE profile, I have the following functions."

Write-Host "Loaded in profile: Measure-Script, Scripts drive" -ForegroundColor Yellow

# Load Module PSProfile Module

# More info http://www.powershellmagazine.com/2013/05/13/measuring-powershell-scripts/

import-module PSProfiler


#Go to default Script folder

Set-Location C:\Scripts\PS


#Set WindowsTitle

((Get-Host).UI.RawUI).WindowTitle = "PowerShell Rocks!"


#Create FileSystem Drive for Script folder

New-PSDrive -Name Scripts -PSProvider FileSystem -Root C:\Scripts\PS | Out-Null

#Script Browser Begin

Function Start-ScriptBrowser


  Add-Type -Path 'C:\Program Files (x86)\Microsoft Corporation\Microsoft Script Browser\System.Windows.Interactivity.dll'

  Add-Type -Path 'C:\Program Files (x86)\Microsoft Corporation\Microsoft Script Browser\ScriptBrowser.dll'

  Add-Type -Path 'C:\Program Files (x86)\Microsoft Corporation\Microsoft Script Browser\BestPractices.dll'

  #Check if ScriptBrowser is already added to AddOnTools

  if (!($psISE.CurrentPowerShellTab.VerticalAddOnTools.Name -eq "Script Browser"))


      $scriptBrowser = $psISE.CurrentPowerShellTab.VerticalAddOnTools.Add('Script Browser', [ScriptExplorer.Views.MainView], $true)


  #Check if ScriptAnalyzer is already added to AddOnTools

  if (!($psISE.CurrentPowerShellTab.VerticalAddOnTools.Name -eq "Script Analyzer"))


    $scriptAnalyzer = $psISE.CurrentPowerShellTab.VerticalAddOnTools.Add('Script Analyzer', [BestPractices.Views.BestPracticesView], $true)


  if (!($psISE.CurrentPowerShellTab.VerticalAddOnTools.Name -eq "Script Browser"))


    $psISE.CurrentPowerShellTab.VisibleVerticalAddOnTools.SelectedAddOnTool = $scriptBrowser




#Script Browser End

"That’s it. I write a blog on TechNet: Stefan Stranger's Weblog - Manage your IT Infrastructure. You can also find me on Twitter."

Jason Walker offers the following ideas:

"I like to use my Windows PowerShell profile to start off my day with a laugh. I do this with the Sapi.SPVoice COM object. When Windows PowerShell is launched, my computer is inspired by LMFAO’s “Party Rock Anthem,” and it informs me that it’s time to shuffle.

"In the following script, first I create the Sapi.SPVoice COM object. Then I switch the voice from David to Zira, and I use Get-Date to get the day of the week to use in the greeting. Lastly, I switch the voice back to David and state the second half of the greeting."

#Create Sapi.Spvoice COM object

$Sapi = New-Object -ComObject sapi.spvoice

#Switch Voice from David to Zira

$Sapi.Voice = $Sapi.GetVoices().Item(2)

#State what "day of the week" shuffle it is

$Sapi.Speak("Time for the $((Get-Date).DayofWeek) shuffle")

#Switch the voice back to David

$Sapi.Voice = $Sapi.GetVoices().Item(0)

#Slow the rate of speach down

$Sapi.Rate = -3

#State last half of greeting

$Sapi.Speak("Everyday I'm shuff-a-linn")

"Yes I know…it's kind of cheesy, but it makes me laugh."

Martin Schvartzman provides the following script to configure a transcript and to import a command's history from previous sessions:

#region Transcript and History management

function Bye() {


    Write-Host "Transcript stopped. Exporting History... " -ForegroundColor Yellow -NoNewline

    Get-History -Count $global:MaximumHistoryCount | Export-Clixml -Path $global:HistoryXmlFilePath

    Write-Host "Finished!" -ForegroundColor Green

    Start-Sleep -Milliseconds 500




function Hi() {

    Start-Transcript -Path $global:Transcript -ErrorAction SilentlyContinue

    if (Test-Path $global:HistoryXmlFilePath) {

       Import-Clixml $global:HistoryXmlFilePath | Add-History }



$global:Transcript = 'C:\Temp\Transcript_{0:yyyyMMddHHmmss}.log' -f (Get-Date)

$global:MaximumHistoryCount = 1500

$global:HistoryXmlFilePath = Join-Path -Path (Split-Path -Path $PROFILE -Parent) -ChildPath PSHistory.xml

$ExitAction = { Bye }

[void](Register-EngineEvent –SourceIdentifier PowerShell.Exiting –Action $ExitAction)



Matt Reynolds doesn’t want his scripts to have accidental dependencies.

"I try to avoid loading things in the profile because I use too many different machines. However, I have a module full of utility functions, which I load and bundle as needed. The following function is a recent addition. It provides memory efficient sums, counts, averages, and so on. It is aggregated by property values. Think of it as a pivot table on a pipeline."



  Measures averages, sums, counts, etc over a series of object with grouping by property values, like a pivot table


  Measures averages, sums, counts, etc over a series of object with grouping by property values, like a pivot table

  Avoids holding all the objects in memory for scalability


  ## Get counts, sums, avgs, etc. for file length by extension

  Get-ChildItem c:\ -Recurse | Measure-MLib__Aggregate -GroupProperty Extension -MeasureProperty Length -OutPipeHt


  ## Get counts, sums, avgs, etc. for multiple numerical columns in a log file while grouping by multiple text columns

  Get-Content -Path somelogfile.txt | ConvertFrom-CSV | Measure-MLib__Aggregate -GroupProperty SourceIp,RequestType -MeasureProperty Size,ResponseTime -OutPipeHt


  Any object(S)


  Varies depending on -Passthru and other parameters


function Measure-MLib__Aggregate{



                ## Input any stream of objects (e.g., psobjects, hashtables, etc.) with

                ## properties that you want to count/sum/average



    ## Causes the input object(s) to be output instead of the measurement object

                ## Use together with $SideOutputHtVariableName or $SideOutputArrayVariableName

                ## to have the measurements sent to a variable while the input objects continue down output pipeline


                ## See Passthru

    [string]$SideOutputHtVariableName = $null,

                ## See Passthru

                [string]$SideOutputArrayVariableName = $null,

                ## One or more property names by which to aggregate


                ## One or more property names by which to measure after aggregation


                ## Causes the measurement results to be output as a flattened table / stream


                ## Causes the measurement results to be output as a hierachial hashtable




    $groups = @{}


    function New-MLib__MeasurementsHashTable{

      param( [string[]]$propertyNames )

      $outer = @{}

      foreach($propertyName in $propertyNames){

        $outer[$propertyName] = @{

          PropertyName = $propertyName

          Count = 0

          Sum = 0

          Avg = 0

          Max = 0

          Min = 0






                function ConvertFrom-MLib__AggregateMeasure{





                        foreach( $aggregateKey in $AggregateMeasure.Keys ){

                                foreach( $propertyMeasure in $AggregateMeasure[$aggregateKey].Values ){

                                        New-Object -TypeName PSCustomObject -Property @{

                                                GroupKey = $aggregateKey

                                                PropertyName = $propertyMeasure["PropertyName"]

                                                Min = $propertyMeasure["Min"]

                                                Max = $propertyMeasure["Max"]

                                                Avg = $propertyMeasure["Avg"]

                                                Count = $propertyMeasure["Count"]

                                                Sum = $propertyMeasure["Sum"]










  process{ foreach( $item in $InputObject ){

    $groupingKey = (@(foreach($propertyName in $GroupProperty){ $item.$propertyName | out-string }) -join ";").Trim()

    if( -not $groups.ContainsKey( $groupingKey )){

      $groups[ $groupingKey ] = New-MLib__MeasurementsHashTable -propertyNames $MeasureProperty


    foreach($measurePropertyName in $MeasureProperty){

      $currentMeasureObject = $groups[$groupingKey][$measurePropertyName]


      $currentMeasureObject.Sum = $currentMeasureObject.Sum + $item.$measurePropertyName

      $currentMeasureObject.Avg = $currentMeasureObject.Sum / $currentMeasureObject.Count

      if( $currentMeasureObject.Min -gt $item.$measurePropertyName ){ $currentMeasureObject.Min = $item.$MeasurePropertyName }

      if( $currentMeasureObject.Max -lt $item.$measurePropertyName ){ $currentMeasureObject.Max = $item.$MeasurePropertyName }



                if( $Passthru ){







                ## TODO FUTURE:

                ## Figure out a way to avoid use of global scope for side output variables.

                ## Every other approach I tried seemed to fail due to crossing of module boundaries


                if(-not ([String]::IsNullOrEmpty($SideOutputHtVariableName) ) ){

                        Set-Variable -Name $SideOutputHtVariableName -Value $groups -Scope GLobal


                if(-not ([String]::IsNullOrEmpty($SideOutputArrayVariableName) ) ){

                        Set-Variable -Name $SideOutputArrayVariableName -Scope Global -Value @(ConvertFrom-MLib__AggregateMeasure $groups)



                if( $OutPipeHt ){




                if( $OutPipeFlat ){

                        ConvertFrom-MLib__AggregateMeasure $groups




That is it for today. Thank you to all the Microsoft PFEs who took time out to contribute to this project. It was fun and educational. Join me tomorrow as I hit up the Windows PowerShell team for what is in their profiles. By the way, what’s in your Windows PowerShell profile? Add a comment in the following text box and let us know.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Like Georges, I have a separator line between commands, I think it's a must-have because it makes it so much easier to separate the outputs of different commands.

    Basically I think these three things are must haves:

    function Set-Debug {
    if ($global:DebugPreference -eq "SilentlyContinue") { $global:DebugPreference = "Continue" }
    else { $global:DebugPreference = "SilentlyContinue" }

    function prompt () { "`n$('-' * (Get-Host).UI.RawUI.WindowSize.Width)`n[$PWD]: " }

    New-Alias "Open" -Value "Start-Process"

    I also have these for creating convenient temp stuff:

    function New-TempFile { [IO.Path]::GetTempFileName() }
    function New-TempDirectory { Join-Path ([System.IO.Path]::GetTempPath()) ([System.GUID]::NewGUID().ToString()) }

    And if you're into signing your scripts, create a wrapper function "Add-Signature" (code is probably obvious?).

  • Added some great stuff to my own profile. Before I had a Set-TitleBar and a Get-Titlebar which help me a lot as I usually have at least 5 PowerShell windows open at any one time. Being able to name windows dynamically based on project is a life saver.

    http://www.genelaisne.com/whats-in-my-profile/ if you're interested.

  • How about changing the font size in the PowerShell console?