Exploiting Your Command History

PowerShell “records” all your interactive command input to its command history, and Get-History shows them. If you played around with PowerShell for a while and then decided that it wasn’t all that bad what you did, here is a script that copies all interactive commands from command history to your clipboard. You can then paste it into the PowerShell ISE, and make it a script:

# define how old your commands may be at most to be included
$MaxAgeHours = 4

# get all command history items that were started after this
$DateLimit = (Get-Date).AddHours(-$MaxAgeHours)


# get all command-line commands
Get-History |
  # exclude all that were aborted
  Where-Object ExecutionStatus -eq Completed |
  # exclude all that are older than the limit set above
  Where-Object StartExecutionTime -gt $DateLimit |
  # get just the command-line
  Select-Object -ExpandProperty CommandLine |
  # copy all to clipboard
  clip.exe

Twitter This Tip! ReTweet this Tip!

Getting Latest PowerShell Gallery Module Version

On www.powershellgallery.com, Microsoft hosts a public script and module repository where you can exchange PowerShell code with others (see more on their site).

To use the repository, you either need PowerShell 5 or install the PowerShellGet module manually (which is available for download on powershellgallery.com). You then have cmdlets like Find/Save/Install/Update/Remove-Script/Module.

What’s missing is a quick way of finding out what the most current version of a published module is. Here is a solution:

function Get-PublishedModuleVersion($Name)
{
   # access the main module page, and add a random number to trick proxies
   $url = "https://www.powershellgallery.com/packages/$Name/?dummy=$(Get-Random)"
   $request = [System.Net.WebRequest]::Create($url)
   # do not allow to redirect. The result is a "MovedPermanently"
   $request.AllowAutoRedirect=$false
   try
   {
     # send the request
     $response = $request.GetResponse()
     # get back the URL of the true destination page, and split off the version
     $response.GetResponseHeader("Location").Split("/")[-1] -as [Version]
     # make sure to clean up
     $response.Close()
     $response.Dispose()
   }
   catch
   {
     Write-Warning $_.Exception.Message
   }
}

Get-PublishedModuleVersion -Name ISESteroids

When you run Get-PublishedModuleVersion and submit the name of a published module, the result looks like this:

 
PS C:> Get-PublishedModuleVersion -Name ISESteroids

Major  Minor  Build  Revision
-----  -----  -----  --------
2      6      3      25      
 

This approach is very, very fast and can be used to check against the versions of installed modules to see whether you are up-to-date.

Twitter This Tip! ReTweet this Tip!

Saving PowerShell User Defaults

We are about to enter “Color Week” with plenty of tips how you can choose better colors for the PowerShell ISE editor and the console. Most changes that you apply to PowerShell are not saved. PowerShell ISE does save some of the color settings, but a more robust way is to place your customizations in one of PowerShell’s profile scripts.

Anything that should be run for any PowerShell host (console as well as PowerShell ISE or any other PowerShell-enabled program) goes here:

 
PS C:> $profile.CurrentUserAllHosts
C:UsersTobiasDocumentsWindowsPowerShellprofile.ps1
 

Anything that applies to a specific host like the console only, or the PowerShell ISE only, goes here:

 
PS C:>  $profile.CurrentUserCurrentHost
C:UsersTobiasDocumentsWindowsPowerShellXXXXXXXXXXXXXX_profile.ps1

Note the “XXX” in the path. You need to run the above line inside the host you want to target. The line returns different paths, depending on the host you are running.

Note also that these calls just provide the path to the profile script. It does not exist by default. You may have to create it, along with the folder “WindowsPowerShell”. When the profile script does exist, it is executed whenever a PowerShell host is launched.

Just make sure script execution is turned on. So you may have to one-time enable script execution, for example like this:

 
PS> Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force 
 

Twitter This Tip! ReTweet this Tip!

Finding ASCII Codes

Here is an easy way to find the ASCII code for any character you may have scraped from a website, or found in a script that you copied from the internet.

Simply open a PowerShell, and enter this:

 
# paste character(s)  inside the quotes 
$text = ''
 
foreach($char in [char[]]$text)
{
  'Character {0,-3} Decimal {1,-5} Hex {1,-4:X}' -f $char, [int]$char
}

Next, paste the character(s) inside the quotes, and run the code. To test-drive, run the following command in PowerShell:

 
PS C:> charmap
 

This opens the character map where you can pick a font, like DingBats for example, and one or more characters. Copy them to the clipboard, then paste them into the PowerShell code above. When you run the code, it returns the ASCII values for the selected characters in decimal and hex form. They should match the values found in the status bar of the character mapper utility.

Twitter This Tip! ReTweet this Tip!

Checking Hard Drive Size (Local and Remote)

WMI can provide the raw data about hard drive size and free space. PowerShell then takes that information and provides user-friendly results like this:

 
PS C:> # local
PS C:> Get-HardDriveSize

DriveLetter Free(GB) Size(GB) Percent
----------- -------- -------- -------
C:             823,7    942,3    87,4



PS C:> # remote
PS C:> Get-HardDriveSize -ComputerName server2 -Credential server2Tobias

DriveLetter Free(GB) Size(GB) Percent
----------- -------- -------- -------
C:              87,3    436,9      20
D:               5,3       25    21,3
 

Here is the code:

function Get-HardDriveSize
{
  param
  (
    $ComputerName,

    $Credential
  )

  # get calculated properties:
  $prop1 = @{
    Name = 'DriveLetter'
    Expression = { $_.DeviceID }
  }

  $prop2 = @{
    Name = 'Free(GB)'
    Expression = { [Math]::Round(($_.FreeSpace / 1GB),1) }
  }

  $prop3 = @{
    Name = 'Size(GB)'
    Expression = { [Math]::Round(($_.Size / 1GB),1) }
  }

  $prop4 = @{
    Name = 'Percent'
    Expression = { [Math]::Round(($_.Freespace * 100 / $_.Size),1) }
  }

  # get all hard drives
  Get-WmiObject -ClassName Win32_LogicalDisk @PSBoundParameters -Filter "DriveType=3" | 
  Select-Object -Property $prop1, $prop2, $prop3, $prop4

}

Twitter This Tip! ReTweet this Tip!

Enabling Remote Administration

PowerShell 2+

Many older DCOM-based commands require a “Remote Administration Firewall Exception” to access remote systems. This includes cmdlets like Get-WmiObject.

One easy way of enabling this is to run the following command in a PowerShell with Administrator privileges:

netsh firewall set service remoteadmin enable

Although this command is considered deprecated, it is still working and one of the easiest ways of configuring the firewall.

Twitter This Tip! ReTweet this Tip!