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

ndasle7k  于 2023-03-12  发布在  Shell
关注(0)|答案(9)|浏览(214)

我想从一个脚本文件中重新加载我的用户配置文件。我以为从脚本文件中获取它会有帮助,但是它不起作用:

# file.ps1
. $PROFILE

然而,如果我不从PowerShell的解释器中获取源代码,它确实可以工作。

我为什么要这么做

我每次更新我的配置文件并想要测试它时都会运行此脚本,因此我希望避免重新启动PowerShell来刷新环境。

tsm1rwdh

tsm1rwdh1#

如果你想从一个脚本全局刷新你的概要文件,你必须运行这个脚本“点源”。
当您运行脚本时,所有概要文件脚本都在“脚本”范围内运行,并且不会修改您的“全局”范围。
为了让脚本修改全局作用域,它需要是“点源代码”或前面有一个句点。

. ./yourrestartscript.ps1

在这里,你的配置文件脚本“dot-sourced”位于“yourrestartscript.ps1”中。你实际上是在告诉“yourrestartscript”在当前作用域中运行,而在该脚本中,你是在告诉$profile脚本在脚本的作用域中运行。由于脚本的作用域是全局作用域,所以配置文件中的任何变量集或命令都将在全局作用域中发生。
这并不能给你带来比逃跑更多的优势

. $profile
j8ag8udp

j8ag8udp2#

因此,您标记为答案的方法可能在PowerShell命令提示符内有效,但在PowerShell伊势(对我来说,它提供了一个上级的PowerShell会话)内无效,并且可能在其他PowerShell环境中也无法正常工作。
这是一个我已经使用了一段时间的脚本,它在任何环境下都能很好地工作。我只是把这个函数放在我的Profile.ps1中~\Documents\WindowsPowerShell,每当我想重新加载我的配置文件时,我都会点源代码这个函数,即:

. Reload-Profile

函数如下:

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

piok6c0g3#

& $profile

用于重新加载配置文件。
如果概要文件设置了别名或执行了失败的导入,那么您将看到错误,因为它们已经在概要文件的上一次加载中设置了。

dfuffjeb

dfuffjeb4#

你为什么要这么做?
因为它很可能会创建重复项(附加到$env:path),并且设置常量/只读对象的问题会导致错误。
最近在microsoft. public. windows. powershell上有一个关于这个主题的帖子。
如果您试图重置会话的状态,则无法做到这一点,即使使用内部作用域($host.EnterNestedPrompt())也不行,因为可以在“所有作用域”设置变量/别名/...。

mlnl4t2r

mlnl4t2r5#

我找到了这个解决方案:

#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
qij5mzcb

qij5mzcb6#

这只是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
}

按理说,它不应该工作,因为它吐出的命令行是畸形的,但它似乎做的工作,这对我来说已经足够好了。

mi7gmzs6

mi7gmzs67#

由于几年后我偶然发现了这一点,我想补充一点,您可以使用调用操作符:&以使用配置文件的默认变量加载配置文件:$profile .
因此,如果您的会话不知何故无法加载您的配置文件(发生在我与cmder/conemu)只需键入:
& $profile

b4lqfgs4

b4lqfgs48#

我用这个来解决什么配置文件是永远需要加载。
开始运行:

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

谢谢你@温斯顿·法塞特让我更接近于找到我的问题。

deyfvvtc

deyfvvtc9#

伪别名(模拟键)

如果您只是想让一个函数在控制台中像别名一样工作,那么只需模拟按键操作以避免使用点源代码。

# 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

相关问题