65

I want to reload my user profile from a script file. I thought that dot sourcing it from within the script file would do the trick, but it doesn't work:

# file.ps1
. $PROFILE

However, it does work if I dot source it from PowerShell's interpreter.

Why do I want to do this?

I run this script every time I update my profile and want to test it, so I'd like to avoid having to restart PowerShell to refresh the environment.

Steffen Opel
  • 63,899
  • 11
  • 192
  • 211
guillermooo
  • 7,915
  • 15
  • 55
  • 58

8 Answers8

51

If you want to globally refresh your profile from a script, you will have to run that script "dot-sourced".

When you run your script, all the profile script runs in a "script" scope and will not modify your "global" scope.

In order for a script to modify your global scope, it needs to be "dot-source" or preceded with a period.

. ./yourrestartscript.ps1

where you have your profile script "dot-sourced" inside of "yourrestartscript.ps1". What you are actually doing is telling "yourrestartscript" to run in the current scope and inside that script, you are telling the $profile script to run in the script's scope. Since the script's scope is the global scope, any variables set or commands in your profile will happen in the global scope.

That doesn't buy you much advantage over running

. $profile
Steven Murawski
  • 10,959
  • 41
  • 53
  • 2
    @Steven: If I put . $PROFILE in the script itself, it doesn't work... That's what I'm trying to do. – guillermooo Feb 20 '09 at 20:20
  • @scott $profile is the full path to the shell specific profile. – Steven Murawski Feb 21 '09 at 00:34
  • "That doesn't buy you much advantage over running" are you implying that `. $profile` does the same thing? – Blake Jul 17 '14 at 08:41
  • The answer looks like it is taken from here: https://newbedev.com/how-to-reload-user-profile-from-script-file-in-powershell but so do some of the other answers. – bgmCoder Jun 16 '22 at 20:52
  • 1
    @bgmCoder newvedev.com didn't exist when I answered this 13 years ago. – Steven Murawski Jun 17 '22 at 00:25
  • haha, then they must have copied it from here - because it's literally word for word. And I believe you. – bgmCoder Jun 17 '22 at 13:54
  • In fact, they *did* copy it from here! Look at this, and I'm quoting: "So, the approach that you marked as the answer may work inside the Powershell command prompt,..." that is taken from one of the other answers on this page. – bgmCoder Jun 17 '22 at 16:04
42

So, the approach that you marked as the answer may work inside the Powershell command prompt, but it doesn't work inside PowerShell ISE (which, to me, provides a superior PowerShell session) and probably won't work right in other PowerShell environments.

Here's a script that I have been using for a while, and it has worked very well for me in every environment. I simply put this function into my Profile.ps1 at ~\Documents\WindowsPowerShell, and whenever I want to reload my profile, I dot-source the function, i.e.

. Reload-Profile

Here's the function:

function Reload-Profile {
    @(
        $Profile.AllUsersAllHosts,
        $Profile.AllUsersCurrentHost,
        $Profile.CurrentUserAllHosts,
        $Profile.CurrentUserCurrentHost
    ) | % {
        if(Test-Path $_){
            Write-Verbose "Running $_"
            . $_
        }
    }    
}
Winston Fassett
  • 3,500
  • 3
  • 36
  • 29
  • "but it doesn't work inside PowerShell ISE (which, to me, provides a superior PowerShell session) and probably won't work right in other PowerShell environments." perhaps you can explain why it doesn't work, since ISE is intended to provide parity with powershell. It's also difficult to find reasons to use powershell over ISE, so this would be nice to know. – Blake Jul 17 '14 at 08:42
  • @Blake: The main reason it just how ISE identifies itself, it uses different default profiles and has a different type of "version". Sadly they are caveats of it being and IDE. https://blogs.msdn.microsoft.com/powershell/2009/04/17/differences-between-the-ise-and-powershell-console/ – ZaxLofful Aug 10 '18 at 21:26
  • 1
    The name of this function uses an unapproved verb (I know, but it makes VSCode nag me whenever I edit my profile.ps1) See this discussion about that: https://stackoverflow.com/questions/54898748/what-powershell-verb-suits-reloading-a-users-profile/54903503#54903503 – stib Feb 28 '19 at 23:06
  • Thanks it reload the profile But how to get rid of the messages like "Set-Variable : Cannot overwrite variable ts_pass because it is read-only or constant. At ...\WindowsPowerShell\Microsoft.PowerShell_profile.ps1:27 char:1" And that because it reloads the CONSTANTS , i guess – CuriousDev May 27 '20 at 17:51
6
& $profile   

works to reload the profile.

If your profile sets aliases or executes imports which fail then you will see errors because they were already set in the previous loading of the profile.

Underverse
  • 1,271
  • 21
  • 32
Lahru
  • 93
  • 1
  • 1
  • 2
    For some reason this doesn't work with newly defined functions – Kellen Stuart Oct 05 '16 at 18:28
  • 5
    This cannot work. `&` is called the [_call operator_](https://ss64.com/ps/call.html) and it creates a new environment scope for the command being executed. This environment is thrown away when the command exits. That means any changes done by the command to the environment are lost. You have to use the [_dot-source operator_](https://ss64.com/ps/source.html) (`.`) instead which executes the command in the current environment. – David Ferenczy Rogožan Aug 09 '19 at 18:52
  • @DavidFerenczyRogožan the & operator is like a subshell in Unix? – Timo Oct 20 '20 at 07:43
  • 1
    I also discourage people to use the `&` operator to source a profile. I used to do it in the past until I found out it was unpredictable. Use `.` instead. – vdsbenoit Mar 17 '22 at 10:16
  • 1
    @Timo, no, `&` runs script _in-process_, but in a _child scope_ - see the conceptual [about_Scopes](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Scopes) help topic. – mklement0 Dec 12 '22 at 20:33
  • @vdsbenoit, `&` isn't unpredictable, its predictable behavior - running a script in a child scope - is simply the wrong tool to use. as shown in David's comment, you need `.` (dot-sourcing). – mklement0 Dec 12 '22 at 20:35
4

Why are you trying to do this?

Because it is likely to create duplicates (appends to $env:path) and problems with setting constant/readonly objects causing errors.

There was a thread on this topic recently on microsoft.public.windows.powershell.

If you are trying to reset the state of the session there is no way to do this, even using an inner scope ($host.EnterNestedPrompt()) because of the ability to set variables/aliases/... at "all scope".

Richard
  • 106,783
  • 21
  • 203
  • 265
2

I found this workaround:

#some-script.ps1

#restart profile (open new powershell session)
cmd.exe /c start powershell.exe -c { Set-Location $PWD } -NoExit
Stop-Process -Id $PID

A more elaborated version:

#publish.ps1
# Copy profile files to PowerShell user profile folder and restart PowerShell
# to reflect changes. Try to start from .lnk in the Start Menu or
# fallback to cmd.exe.
# We try the .lnk first because it can have environmental data attached
# to it like fonts, colors, etc.

[System.Reflection.Assembly]::LoadWithPartialName("System.Diagnostics")

$dest = Split-Path $PROFILE -Parent
Copy-Item "*.ps1" $dest -Confirm -Exclude "publish.ps1" 

# 1) Get .lnk to PowerShell
# Locale's Start Menu name?...
$SM = [System.Environment+SpecialFolder]::StartMenu
$CurrentUserStartMenuPath = $([System.Environment]::GetFolderPath($SM))
$StartMenuName = Split-Path $CurrentUserStartMenuPath -Leaf                                 

# Common Start Menu path?...
$CAD = [System.Environment+SpecialFolder]::CommonApplicationData
$allUsersPath = Split-Path $([System.Environment]::GetFolderPath($CAD)) -Parent
$AllUsersStartMenuPath = Join-Path $allUsersPath $StartMenuName

$PSLnkPath = @(Get-ChildItem $AllUsersStartMenuPath, $CurrentUserStartMenuPath `
                                        -Recurse -Include "Windows PowerShell.lnk")

# 2) Restart...
# Is PowerShell available in PATH?
if ( Get-Command "powershell.exe" -ErrorAction SilentlyContinue ) {

    if ($PSLnkPath) {

        $pi = New-Object "System.Diagnostics.ProcessStartInfo"
        $pi.FileName = $PSLnkPath[0]
        $pi.UseShellExecute = $true

        # See "powershell -help" for info on -Command
        $pi.Arguments = "-NoExit -Command Set-Location $PWD"

        [System.Diagnostics.Process]::Start($pi)
    }
    else { 

        # See "powershell -help" for info on -Command
        cmd.exe /c start powershell.exe -Command { Set-Location $PWD } -NoExit
    }
}
else {
    Write-Host -ForegroundColor RED "Powershell not available in PATH."
}

# Let's clean up after ourselves...
Stop-Process -Id $PID
guillermooo
  • 7,915
  • 15
  • 55
  • 58
0

This is only a refinement of the two line script in guillermooo's answer above, which did not get the new PowerShell window into the correct directory for me. I believe this is because $PWD is evaluated in the new PowerShell window's context, which is not the value we want set-location to process.

function Restart-Ps {
$cline = "`"/c start powershell.exe -noexit -c `"Set-Location '{0}'" -f $PWD.path
cmd $cline
Stop-Process -Id $PID
}

By rights it shouldn't work, as the command line it spits out is malformed, but it seems to do the job and that's good enough for me.

Alex
  • 1,249
  • 1
  • 14
  • 14
0

I used this to troubleshoot what profile was taking forever to load.

Start Run:

powershell_ise -noprofile

Then i ran this:

function Reload-Profile {
    @(
        $Profile.AllUsersAllHosts,
        $Profile.AllUsersCurrentHost,
        $Profile.CurrentUserAllHosts,
        $Profile.CurrentUserCurrentHost
    ) | % {
        if(Test-Path $_){
            Write-Verbose "Running $_"
            $measure = Measure-Command {. $_}
            "$($measure.TotalSeconds) for $_"
        }
    }    
}

. Reload-Profile

Thank you @Winston Fassett for getting me closer to finding my issue.

Omzig
  • 861
  • 1
  • 12
  • 20
0

Pseudo Alias (simulate keys)

If you just want a function to work like an alias in the console, just simulate the key presses to get around having to use the dot source.

# when "reload" is typed in the terminal, the profile is reloaded
# use sendkeys to send the enter key to the terminal
function reload {
    Add-Type -AssemblyName System.Windows.Forms
    [System.Windows.Forms.SendKeys]::SendWait(". $")
    [System.Windows.Forms.SendKeys]::SendWait("PROFILE")
    [System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
}

screenshot of it working

Coyboy
  • 1