Как перезагрузить профиль пользователя из файла сценария в PowerShell

StackOverflow https://stackoverflow.com/questions/567650

  •  05-09-2019
  •  | 
  •  

Вопрос

Я хочу перезагрузить свой профиль пользователя из файла скрипта.Я думал, что точка, извлекающая его из файла сценария, сделает свое дело, но это не сработало:

# file.ps1
. $PROFILE

Однако это действительно работает, если я использую исходный код из интерпретатора PowerShell.

Почему я хочу это сделать?

Я запускаю этот скрипт каждый раз, когда обновляю свой профиль, и хочу протестировать его, поэтому я хотел бы избежать необходимости перезапускать PowerShell для обновления среды.

Это было полезно?

Решение

Итак, подход, который вы отметили как ответ, может работать в командной строке Powershell, но он не работает в PowerShell ISE (который, на мой взгляд, обеспечивает улучшенный сеанс 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 $_"
            . $_
        }
    }    
}

Другие советы

Если вы хотите глобально обновить свой профиль с помощью скрипта, вам придется запустить этот скрипт "с точечным исходным кодом".

Когда вы запускаете свой скрипт, весь скрипт профиля выполняется в области "script" и не изменяет вашу "глобальную" область.

Для того чтобы скрипт изменил вашу глобальную область видимости, ему должен быть указан "точечный источник" или перед ним должна стоять точка.

. ./yourrestartscript.ps1

где у вас есть скрипт вашего профиля с "точечным исходным кодом" внутри "yourestartscript.ps1".Что вы на самом деле делаете, так это указываете "yourestartscript" на запуск в текущей области видимости, а внутри этого скрипта вы указываете скрипту $profile на запуск в области видимости скрипта.Поскольку область действия скрипта является глобальной, любые переменные или команды в вашем профиле будут выполняться в глобальной области.

Это не дает вам большого преимущества перед бегом

. $profile
& $profile   

работает для перезагрузки профиля.

Если ваш профиль устанавливает псевдонимы или выполняет импорт с ошибкой, то вы увидите ошибки, поскольку они уже были установлены при предыдущей загрузке профиля.

Почему ты пытаешься это сделать?

Потому что это, скорее всего, приведет к созданию дубликатов (добавляется к $env: path) и проблемам с установкой объектов constant / readonly, вызывающих ошибки.

Недавно была тема на эту тему на microsoft.общедоступный.windows.powershell.

Если вы пытаетесь сбросить состояние сеанса, это невозможно сделать, даже используя внутреннюю область ($host.EnterNestedPrompt()) из-за возможности устанавливать переменные / псевдонимы/...на "всем размахе".

Я нашел это обходное решение:

#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

Это всего лишь доработка двухстрочного скрипта в ответе 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
}

По правилам это не должно работать, так как командная строка, которую он выдает, искажена, но, похоже, она справляется со своей задачей, и для меня этого достаточно.

Я использовал это для устранения неполадок, из-за которых загрузка профиля занимала целую вечность.

Начать Выполнять:

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 за то, что приблизили меня к поиску моей проблемы.

поскольку я наткнулся на это несколько лет спустя, я подумал добавить, что вы можете использовать оператор вызова: & чтобы загрузить ваш профиль с переменной по умолчанию в ваш профиль: $profile.

итак, если вашему сеансу каким-то образом не удается загрузить ваш профиль (такое случается со мной с cmder / conemu), просто введите:

& $profile

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top