PowerShell: Sync Profile Script from Work to Home
There’s a potential .ps1 file that can be created and edited so that every time you open the PowerShell ConsoleHost things run in the background, as the session begins. I use it to initialize variables, to create aliases, to declare functions, and more. In regard to Profiles, here’s an old Scripting Guy article that may be of help if you need it.
We’ve broken the structure of the profile script template into three logical parts. Have a look at the first section of the template below, and then we’ll discuss it.
$WorkComputer = 'WorkComputer'
$HomeComputer = 'HomeComputer'
Switch ($env:COMPUTERNAME) {
# Work computer only.
{$_ -eq $WorkComputer} {
} # End work computer only.
# Home computer only.
{$_ -eq $HomeComputer} {
} # End home computer only.
# Work and home computer.
{$_ -eq $WorkComputer -or $_ -eq $HomeComputer} {
} # End Work and home computer.
} # End Switch.
In lines 1 and 2, we create two variables, $WorkComputer and $HomeComputer. As you might expect, these variables store the computer names of my work, and my home computers. If you choose to use this template, then these variable assignments will require a small bit of manual editing on your own; however, it's a one time thing, and in my mind, a small price to pay to have your profile synced between two computers.
Following these two variable assignments, is the above Switch statement. This defines what will be available on the two different computers. The first section in the Switch are things I only want available on my work computer, the second section are things I only want available on my home computer only, and the last section is for things that I want available on both my work and home computer. This last section is where I placed my prompt function, for instance, in order that it's available regardless of where I'm working. I really don't want to be without it.
At the end of this post, I'll included the full, uninterrupted code, but for now, let's have a look at the next section. This section defines the Sync-ProfileScript function.
# Create Sync profile function.
Function Sync-ProfileScript {
[CmdletBinding()]
Param (
[Parameter(Mandatory=$true)]
[ValidateSet('Source','Destination')]
[string]$ComputerType,
[Parameter()]
[string]$LocalProfileScriptPath = "$env:USERPROFILE\Dropbox\PowerShell\Profile\Microsoft.PowerShell_profile.ps1"
)
Begin {
# Exit if NOT the ConsoleHost.
If (-Not($Host.Name -eq 'ConsoleHost')) {
break
}
} # End Begin.
Process {
If (Test-Path -Path $PROFILE) {
$CompareFiles = Compare-Object -ReferenceObject (Get-Item $PROFILE).LastWriteTime -DifferenceObject (Get-Item $LocalProfileScriptPath).LastWriteTime -IncludeEqual |
Select-Object -First 1
If ([System.Boolean]($CompareFiles.SideIndicator -ne '==')) {
Switch ($ComputerType) {
'Source' {Copy-Item -Path $PROFILE -Destination $LocalProfileScriptPath}
'Destination' {
Copy-Item -Path $LocalProfileScriptPath -Destination $PROFILE
'Profile Script has been updated. Restart ConsoleHost?'
Do {
$Prompt = Read-Host -Prompt 'Enter r to Restart or c to Cancel'
} Until ($Prompt -eq 'r' -or $Prompt -eq 'c')
If ($Prompt -eq 'r') {
Start-Process -FilePath powershell.exe
Stop-Process -Id $PID
}
}
} # End Switch.
} # End If.
} # End If.
} # End Process.
End {
} # End End.
} # End Function: Sync-ProfileScript.
**
The purpose of the Sync-ProfileScript function is to copy the profile script to a Dropbox folder, when the ConsoleHost is opened on the work computer. Additionally, it serves to copy the profile script from that same Dropbox folder, when the ConsoleHost is opened on the home computer.** Keep in mind that I've purposely written this function to always go from the work computer, to the home computer. I don't plan to make changes in the profile script on the home computer, that I'll then expect or want, on the work computer.
Let's cover what's happening in this function. In lines 1 - 11 we define out Sync-ProfileScript function with two parameters: ComputerType and LocalProfileScriptPath. We use the ComputerType parameter to indicate whether this is the source or destination computer. Source is work and destination is home. The LocalProfileScriptPath parameter points to the profile script (.ps1 file), located in Dropbox. As it has a default value, I don't have to send in a parameter value when the function is invoked.
Our Begin block serves one quick purpose and that's to exit the function immediately, if we're not in the ConsoleHost, and instead inside a host such as the ISE. The magic happens in the Process block. Here's what we do, in order: (1) Test to see that there's an actual profile script being used, (2) if there is, compare the LastWriteTime on the profile script file used by the ConsoleHost ($PROFILE), and the file in Dropbox, (3) if they are different, either copy the profile script used by the ConsoleHost to Dropbox, or copy the profile script in Dropbox to the location used by the ConsoleHost. Again, this is dependent on which computer we're using: work or home.
Let's stop and consider something from the perspective of the home computer. If I open the PowerShell ConsoleHost there, it'll potentially download the newest version of the profile script from Dropbox to its place on the filesystem. Great. The problem is that any changes to the profile script won't be usable until the next time that ConsoleHost is started. I think I could've run & $PROFILE, but I skipped that option as I vaguely remember that it didn't always work for me.
Therefore, I added a bit more code. If the home computer notices a change to the profile script, it'll indicate that to the user by writing "Profile Script has been updated. Restart ConsoleHost?" and "Enter r to Restart or c to Cancel." If the user enters "r," it'll restart the ConsoleHost loading the newest version of the profile script by default. If the user enters "c," it'll cancel the ConsoleHost restart and the newest version of the profile script will not be updated on the home computer. It will, however, be updated the next time a ConsoleHost is opened.
Now, on to the final portion of my profile script. Don't worry, this part is less involved than the Sync-ProfileScript function.
# Determine if sync counter variable exists.
If (-Not($env:SyncProfileCounter)) {
$env:SyncProfileCounter = 0
# Copy profile script to/from Dropbox by calling Sync-ProfileScript.
If ($env:COMPUTERNAME -eq $WorkComputer) {
Sync-ProfileScript -ComputerType Source
} ElseIf ($env:COMPUTERNAME -eq $HomeComputer) {
Sync-ProfileScript -ComputerType Destination
} # End If-ElseIf.
} # End If.
This section of the profile script invokes the Sync-ProfileScript function we discussed in the last section. If it's run on the work computer, it indicates to the Sync-ProfileScript function to copy the profile script to Dropbox. If it's run on the home computer, it indicates to the function to copy the profile script from Dropbox. We know this already, however. It uses a counter variable stored inside an environmental variable to ensure this If statement doesn't perpetually run, and therefore perpetually call the Sync-ProfileScript function. I won't a separate post about that here.
I realize that not everyone is using Dropbox. If you're using another service, then I highly suspect you can use what you've learned here, with them as well. You'll just need to determine the local path to use, and adjust your profile script accordingly. If someone wants to let me know about OneDrive, that would be great. I'd be more than happy to include that information in this post!
Here's the complete profile script template.
$WorkComputer = 'WorkComputer'
$HomeComputer = 'HomeComputer'
Switch ($env:COMPUTERNAME) {
# Work computer only.
{$_ -eq $WorkComputer} {
} # End work computer only.
# Home computer only.
{$_ -eq $HomeComputer} {
} # End home computer only.
# Work and home computer.
{$_ -eq $WorkComputer -or $_ -eq $HomeComputer} {
} # End Work and home computer.
} # End Switch.
# Create Sync profile function.
Function Sync-ProfileScript {
[CmdletBinding()]
Param (
[Parameter(Mandatory=$true)]
[ValidateSet('Source','Destination')]
[string]$ComputerType,
[Parameter()]
[string]$LocalProfileScriptPath = "$env:USERPROFILE\Dropbox\PowerShell\Profile\Microsoft.PowerShell_profile.ps1"
)
Begin {
# Exit if NOT the ConsoleHost.
If (-Not($Host.Name -eq 'ConsoleHost')) {
break
}
} # End Begin.
Process {
If (Test-Path -Path $PROFILE) {
$CompareFiles = Compare-Object -ReferenceObject (Get-Item $PROFILE).LastWriteTime -DifferenceObject (Get-Item $LocalProfileScriptPath).LastWriteTime -IncludeEqual |
Select-Object -First 1
If ([System.Boolean]($CompareFiles.SideIndicator -ne '==')) {
Switch ($ComputerType) {
'Source' {Copy-Item -Path $PROFILE -Destination $LocalProfileScriptPath}
'Destination' {
Copy-Item -Path $LocalProfileScriptPath -Destination $PROFILE
'Profile Script has been updated. Restart ConsoleHost?'
Do {
$Prompt = Read-Host -Prompt 'Enter r to Restart or c to Cancel'
} Until ($Prompt -eq 'r' -or $Prompt -eq 'c')
If ($Prompt -eq 'r') {
Start-Process -FilePath powershell.exe
Stop-Process -Id $PID
}
}
} # End Switch.
} # End If.
} # End If.
} # End Process.
End {
} # End End.
} # End Function: Sync-ProfileScript.
# Determine if sync counter variable exists.
If (-Not($env:SyncProfileCounter)) {
$env:SyncProfileCounter = 0
# Copy profile script to/from Dropbox by calling Sync-ProfileScript.
If ($env:COMPUTERNAME -eq $WorkComputer) {
Sync-ProfileScript -ComputerType Source
} ElseIf ($env:COMPUTERNAME -eq $HomeComputer) {
Sync-ProfileScript -ComputerType Destination
} # End If-ElseIf.
} # End If.
This has also been posted at http://tommymaynard.com/sync-profile-script-from-work-to-home-2017.