Summary: Ed Wilson, Microsoft Scripting Guy, talks about replacing one Windows PowerShell function with a different one.
Microsoft Scripting Guy, Ed Wilson, is here. One of the problems with writing Windows PowerShell code every day is that you eventually...
No, it’s not what you think.
I am often asked if I run out of ideas, and the answer is, "No, I don’t."
There is so much I can do with Windows PowerShell that, in fact, a new version of Windows PowerShell will be out before I ever run out of ideas of what to do with the last version. No, the problem is not that I run out of ideas, but it is that I often forget what I have written. In fact, this week is a case in point.
Code cleanup
I wrote a cool function that creates a Windows PowerShell transcript log file name from the date. In it, I replace invalid file-name characters. Here is the function:
Function Get-TranscriptName
{
$invalidChars = [io.path]::GetInvalidFileNamechars()
$date = Get-Date -format s
"{0}.{1}.{2}.txt" -f "PowerShell_Transcript", $env:COMPUTERNAME,
($date.ToString() -replace "[$invalidChars]","-") }
There is absolutely nothing in the world wrong with it. It works fine (that is, if I don’t start Windows PowerShell twice in the same second, which on my laptop is virtually impossible to do).
The problem is that I have already written a cool Windows PowerShell function that will remove invalid characters from the file name. So THAT is why I knew about [io.path]::GetInvalidFileNameChars. I didn’t even have to look it up—I remembered it because I have used it before. Here is that function:
Function Replace-InvalidFileCharacters
{
Param ($stringIn,
$replacementChar)
# Replace-InvalidFileCharacters "my?string"
# Replace-InvalidFileCharacters (get-date).tostring()
$stringIN -replace "[$( [System.IO.Path]::GetInvalidFileNameChars() )]", $replacementChar
}
It is obvious, that the code is essentially the same, but it has the added advantage that I can use it for any string, not just for the date. So, I decided that I want to add this function to my Windows PowerShell profile and cleanup the Windows PowerShell transcript name function a bit. But how?
How do I bring in this function and cleanup the other function, when the Get-TranscriptName function has the functionality embedded into a rather complex line of Windows PowerShell code?
Add them to a blank page in the ISE
The answer is pretty simple:
I open a new tab in the Windows PowerShell ISE, and I test it out. First I open my Windows PowerShell profile from the Windows PowerShell console by using my function Edit-Profile Windows PowerShell.
Then I add a new blank page to the Windows PowerShell ISE, and I copy the Get-TranscriptName and the Replace-InvalidFileCharacters functions to it. This is shown here:
Reduce duplication
Now I need to look at what the Replace-InvalidFileCharacters function does and what I need to have in the Get-TranscriptName function. It is obvious that the key to both functions is the call to GetInvalidFileNameChars static method. So, I can comment out the first line in the Get-TranscriptName function:
Function Get-TranscriptName
{
#$invalidChars = [io.path]::GetInvalidFileNamechars()
$date = Get-Date -format s
"{0}.{1}.{2}.txt" -f "PowerShell_Transcript", $env:COMPUTERNAME,
($date.ToString() -replace "[$invalidChars]","-") }
The next thing that the Replace-InvalidFileCharacters function does is call the –Replace operator to replace the invalid characters with the character supplied when the function is called. So I can also replace that line in my Get-TranscriptName function:
In the previous image, you can see that the two commands are essentially the same:
-Replace (characters to replace), (character to replace with)
Because the Replace-InvalidFileCharacters function performs the same thing as the code highlighted in the Get-TranscriptName, I can substitute the code in the Get-TranscriptName function with a call to the Replace-InvalidFileCharacters function.
I need to first load the Replace-InvalidFileCharacters function into memory in my Windows PowerShell ISE so I can test it to make sure everything works properly.
The other thing I need to realize is that the (Get-Date).tostring() portion in my Get-TranscriptFileName function will need to be supplied as input to the Replace-InvalidFileCharacters function. So, here is the replacement:
Function Get-TranscriptName
{
$date = Get-Date -format s
"{0}.{1}.{2}.txt" -f "PowerShell_Transcript", $env:COMPUTERNAME,
(Replace-InvalidFileCharacters -stringIn $date.ToString() -replacementChar "-") }
Now, in keeping with my tenant that I like to create aliases for my functions, I create a new alias for Replace-InvalidFileCharacters that will be easier to type. I decide to see if RIFC is taken. I test it with Get-Alias:
PS C:\> Get-Alias rifc
Get-Alias : This command cannot find a matching alias because an alias with the name 'rifc' does not exist.
At line:1 char:1
+ Get-Alias rifc
+ ~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (rifc:String) [Get-Alias], ItemNotFoundException
+ FullyQualifiedErrorId : ItemNotFoundException,Microsoft.PowerShell.Commands.GetAliasCommand
It appears to be available, so I add this alias:
Set-Alias -Name rifc -Value Replace-InvalidFileCharacters | out-null
Then I copy the two functions to my Windows PowerShell profile after I replace the long command name. The complete profile is shown here:
#------------------------------------------------------------------------------
#
# PowerShell console profile
# ed wilson, msft
#
# NOTES: contains five types of things: aliases, functions, psdrives,
# variables and commands.
# version 1.1
# 7/20/2015
# HSG 7-23-2015
#------------------------------------------------------------------------------
#Aliases
Set-Alias -Name ep -Value edit-profile | out-null
Set-Alias -Name tch -Value Test-ConsoleHost | out-null
Set-Alias -Name gfl -Value Get-ForwardLink | out-null
Set-Alias -Name gwp -Value Get-WebPage | out-null
Set-Alias -Name rifc -Value Replace-InvalidFileCharacters | out-null
#Functions
Function Edit-Profile
{ ISE $profile }
Function Test-ConsoleHost
{
if(($host.Name -match 'consolehost')) {$true}
Else {$false}
}
Function Replace-InvalidFileCharacters
{
Param ($stringIn,
$replacementChar)
# Replace-InvalidFileCharacters "my?string"
# Replace-InvalidFileCharacters (get-date).tostring()
$stringIN -replace "[$( [System.IO.Path]::GetInvalidFileNameChars() )]", $replacementChar
}
Function Get-TranscriptName
{
$date = Get-Date -format s
"{0}.{1}.{2}.txt" -f "PowerShell_Transcript", $env:COMPUTERNAME,
(rifc -stringIn $date.ToString() -replacementChar "-") }
Function Get-WebPage
{
Param($url)
# Get-WebPage -url (Get-CmdletFwLink get-process)
(New-Object -ComObject shell.application).open($url)
}
Function Get-ForwardLink
{
Param($cmdletName)
# Get-WebPage -url (Get-CmdletFwLink get-process)
(Get-Command $cmdletName).helpuri
}
#Variables
New-Variable -Name doc -Value "$home\documents"
#PS_Drives
New-PSDrive -Name Mod -Root ($env:PSModulePath -split ';')[0] `
-PSProvider FileSystem | out-null
#Commands
Set-Location c:\
If(tch) {Start-Transcript -Path (Join-Path -Path `
$doc -ChildPath $(Get-TranscriptName))}
On Monday, I'll wrap up Profile Week, and I'll be talking about adding variable descriptions to my profile. 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