如何从 PowerShell 中的脚本文件重新加载用户配置文件

问题描述 投票:0回答:9

我想从脚本文件重新加载我的用户配置文件。我认为从脚本文件中获取它的点可以解决问题,但它不起作用:

# file.ps1
. $PROFILE

但是,如果我不从 PowerShell 的解释器获取它,它确实可以工作。

我为什么要这么做?

我每次更新个人资料并想要测试它时都会运行此脚本,因此我希望避免重新启动 PowerShell 来刷新环境。

powershell profile
9个回答
56
投票

如果您想从脚本全局刷新您的个人资料,您将必须运行该脚本“dot-sourced”。

当您运行脚本时,所有配置文件脚本都在“脚本”范围内运行,并且不会修改您的“全局”范围。

为了让脚本修改全局范围,它需要是“点源”或前面加一个句点。

. ./yourrestartscript.ps1

您的配置文件脚本位于“yourrestartscript.ps1”内的“点源”。 您实际上正在做的是告诉“yourrestartscript”在当前范围内运行,并且在该脚本内,您正在告诉 $profile 脚本在该脚本的范围内运行。 由于脚本的作用域是全局作用域,因此您的配置文件中的任何变量集或命令都将发生在全局作用域中。

这并不会给你带来比跑步更多的优势

. $profile

52
投票

因此,您标记为答案的方法可能在 Powershell 命令提示符中有效,但在 PowerShell ISE 中不起作用(对我来说,它提供了卓越的 PowerShell 会话),并且可能无法在其他 PowerShell 中正常工作环境。

这是我已经使用了一段时间的脚本,它在每个环境中都对我来说非常有效。 我只需将此函数放入 ~\Documents\WindowsPowerShell 中的 Profile.ps1 中,每当我想重新加载我的配置文件时,我都会对该函数进行点源化,即

. Reload-Profile

功能如下:

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

7
投票
& $profile   

可以重新加载配置文件。

如果您的配置文件设置别名或执行失败的导入,那么您将看到错误,因为它们已在之前加载配置文件时设置。


4
投票

你为什么要尝试这样做?

因为它可能会创建重复项(附加到 $env:path)并且设置常量/只读对象会导致错误。

最近在 microsoft.public.windows.powershell 上有一个关于此主题的主题。

如果您尝试重置会话的状态,即使使用内部范围(

$host.EnterNestedPrompt()
)也无法做到这一点,因为能够在“所有范围”设置变量/别名/...。


2
投票

我找到了这个解决方法:

#some-script.ps1

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

更详细的版本:

#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

2
投票

伪别名(模拟按键)

如果您只想让函数像控制台中的别名一样工作,只需模拟按键即可避免使用点源。

# 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}")
}

它的工作截图


0
投票

这只是上面 guillermooo 的答案中两行脚本的改进,它没有将新的 PowerShell 窗口放入正确的目录中。我相信这是因为 $PWD 是在新的 PowerShell 窗口的上下文中计算的,这不是我们想要 set-location 处理的值。

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

按理说它不应该工作,因为它输出的命令行格式错误,但它似乎可以完成工作,这对我来说已经足够好了。


0
投票

我用它来解决什么配置文件永远无法加载的问题。

开始运行:

powershell_ise -noprofile

然后我运行了这个:

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

感谢@Winston Fassett 让我更接近找到我的问题。


0
投票

我发现的另一种选择是重新启动会话:

function rl { # Reload powershell
    Write-Output "Restarting powershell..."
    & powershell -NoExit -Command "Set-Location -Path $(Get-Location)"
    exit
}
© www.soinside.com 2019 - 2024. All rights reserved.