56

I am writing automated script for cloning GitHub source code to local machine.
I failed after installing Git in my script, it asked for close/open powershell.
So I am not able to clone code automatic after installing Git.

Here is my code:

iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
 choco install -y git
 refreshenv
 Start-Sleep -Seconds 15

 git clone --mirror https://${username}:${password}@$hostname/${username}/$Projectname.git D:\GitTemp -q 2>&1 | %{ "$_" } 

Error:

git : The term 'git' is not recognized as the name of a cmdlet, 
      function, script file, or operable program. 
      Check the spelling of the name, or if a path was included, 
      verify that the path is correct and try again.

Please let me what should I put for reboot PowerShell without exiting?

mklement0
  • 382,024
  • 64
  • 607
  • 775
Priya Rani
  • 1,063
  • 3
  • 11
  • 21

4 Answers4

79

You have a bootstrapping problem:

  • refreshenv (an alias for Update-SessionEnvironment) is generally the right command to use to update the current session with environment-variable changes after a choco install ... command.

  • However, immediately after installing Chocolatey itself, refreshenv / Update-SessionEnvironment themselves are only available in future PowerShell sessions, because loading these commands happens via code added to profile $PROFILE, based on environment variable $env:ChocolateyInstall.

That said, you should be able to emulate what Chocolatey does when $PROFILE is sourced in future sessions in order to be able to use refreshenv / Update-SessionEnvironment right away, immediately after installing Chocolatey:

iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

choco install -y git

# Make `refreshenv` available right away, by defining the $env:ChocolateyInstall
# variable and importing the Chocolatey profile module.
# Note: Using `. $PROFILE` instead *may* work, but isn't guaranteed to.
$env:ChocolateyInstall = Convert-Path "$((Get-Command choco).Path)\..\.."   
Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"

# refreshenv is now an alias for Update-SessionEnvironment
# (rather than invoking refreshenv.cmd, the *batch file* for use with cmd.exe)
# This should make git.exe accessible via the refreshed $env:PATH, so that it
# can be called by name only.
refreshenv

# Verify that git can be called.
git --version

Note: The original solution used . $PROFILE instead of Import-Module ... to load the Chocolatey profile, relying on Chocolatey to have updated $PROFILE already at that point. However, ferventcoder points out that this updating of $PROFILE doesn't always happen, so it cannot be relied upon.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • 2
    profile reload is a must, otherwise sometimes refreshenv fails to work! – Pikesh Prasoon Apr 05 '18 at 13:30
  • @mklement0 it would be great if you could quote the source from `feventcoder`. I know it's accurate, but I'd love to see some of the context why that might be the case – Mattisdada Jun 22 '20 at 00:50
  • @Mattisdada: My understanding is that `$PROFILE` is updated only if that file _already exists_, but I have no official documentation to point to, so I suggest you ask \@ferventcoder himself. – mklement0 Jun 22 '20 at 01:58
  • 2
    If you like to assume (I am bad about it), you can also use `Import-Module "$env:ProgramData\chocolatey\helpers\chocolateyInstaller.psm1"; Update-SessionEnvironment` where the `$env:ProgramData\chocolatey` is the default path where chocolatey will install itself. – dragon788 Nov 02 '20 at 22:53
  • to use refreshenv outside of choco fetch `Get-EnvironmentVariable.ps1, Get-EnvironmentVariableNames.ps1, Update-SessionEnvironment.ps1, Write-FunctionCallLogMessage.ps1` from https://github.com/chocolatey/choco/tree/stable/src/chocolatey.resources/helpers/functions and `Import-Module ...` on each of them. – matt wilkie Jan 06 '22 at 23:39
4

NEW:

The old approach I originally answered with has a few quirks with environment variables that use a ; delimiter. I tried compensated by handling PATH seperately, but sometimes there are other such variables.

So this is the new approach; you might want to put it in a script or something. It has to nest a couple of powershell processes real quick, which isn't ideal, but it's the only reliable way I've found to escape the active environment and capture the output.

# Call a powershell process to act as a wrapper to capture the output:
& ([Diagnostics.Process]::GetCurrentProcess().ProcessName) -NoP -c (
# String wrapper to help make the code more readable through comma-separation:
[String]::Join(' ', (
# Start a process that escapes the active environment:
'Start-Process', [Diagnostics.Process]::GetCurrentProcess().ProcessName,
'-UseNewEnvironment -NoNewWindow -Wait -Args ''-c'',',
# List the environment variables, separated by a tab character:
'''Get-ChildItem env: | &{process{ $_.Key + [char]9 + $_.Value }}'''
))) | &{process{
  # Set each line of output to a process-scoped environment variable:
  [Environment]::SetEnvironmentVariable(
    $_.Split("`t")[0], # Key
    $_.Split("`t")[1], # Value
    'Process'          # Scope
  )
}}

OLD:

Did my best to try and make it a one-liner, but since the PATH variable needs special handling, I couldn't do it without making a stupidly long line. On the plus side, you don't need to rely on any third-party modules:

foreach ($s in 'Machine','User') {
  [Environment]::GetEnvironmentVariables($s).GetEnumerator().
  Where({$_.Key -ne 'PATH'}) | ForEach-Object {
    [Environment]::SetEnvironmentVariable($_.Key,$_.Value,'Process') }}

$env:PATH = ( ('Machine','User').ForEach({
  [Environment]::GetEnvironmentVariable('PATH',$_)}).
  Split(';').Where({$_}) | Select-Object -Unique ) -join ';'

The code is scoped to the process, so you don't have to worry about anything getting messed up (not that it would, I tested it).


Note: Neither approach removes uniquely-named environment variables that were created in your active environment, so if you defined $env:FOO = 'bar' and 'FOO' is not normally one of your environment variables, $env:FOO will still return bar even after any of the above code is ran.

Vopel
  • 662
  • 6
  • 11
  • Upvoted for being a version of choco Update-SessionEnvironment that doesn't depend on other choco functions to run. Solved a problem for me, thanks. – user1169420 Dec 07 '21 at 01:47
3

You can try and use Update-SessionEnvironment:

Updates the environment variables of the current powershell session with any environment variable changes that may have occured during a Chocolatey package install.

That will test if that change is still effective after the chocolatey call.

If not, one easy workaround would be at least to use an absolute path for calling git.

To call Git from Powershell:

new-item -path alias:git -value 'C:\Program Files\Git\bin\git.exe'

Then you can try:

git clone --mirror https://${username}:${password}@$hostname/${username}/$Projectname.git D:\GitTemp -q 2>&1 | %{ "$_" } 
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • @PriyaRani That is what I suggested as an alternative to use the full path for Git: `C:\path\to\git.exe clone --mirror ...` – VonC Oct 15 '17 at 19:39
  • But SIr , I want one time run command after installed git, it should clone repo ..... If I am passing path of git ,it throws error path is not recognized..., **C:\Program : The term 'C:\Program' is not recognized as the name of a cmdlet, function** iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) choco install -y git refreshenv Start-Sleep -Seconds 15 git clone --mirror https://${username}:${password}@$hostname/${username}/$Projectname.git D:\G – Priya Rani Oct 15 '17 at 20:09
  • @PriyaRani Use quotes: `"C:\Program Files\path\to\git.exe" clone...` – VonC Oct 15 '17 at 20:12
  • getting issue while putting quotes :- "Unexpected token 'clone' in expression or statement" .......... "C:\Program Files\Git\bin\git.exe" clone https://github.com/Priyaran ... + ~~~~~ Unexpected token 'clone' in expression or statement. + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : UnexpectedToken – Priya Rani Oct 15 '17 at 20:24
  • @PriyaRani Maybe you cannot call directly the command from the Powershell script: see https://github.com/PowerShell/PowerShell/issues/1583 – VonC Oct 15 '17 at 20:27
  • 1
    The OP indeed tried to use `Update-SessionEnvironment`, namely via its `refreshenv` alias, but the problem is that these commands aren't available yet immediately after a Chocolatey installation. While your alias definition command works, a simpler and more idiomatic definition is `Set-Alias git 'C:\Program Files\Git\bin\git.exe'`. Also, while your approach happens to work with `git`, not all packages installed by Chocolatey are installed into the usual locations, so a more robust approach is to find a way to bootstrap the use of `Update-SessionEnvironment` / `refreshenv`. – mklement0 Oct 15 '17 at 22:53
2

I go with the lo-tech solution:

$env:Path += ";C:\Program Files\Git\bin"
Caltor
  • 2,538
  • 1
  • 27
  • 55
  • 2
    It is super broken that the choco install for git doesn't just do this for you – A X Jul 01 '22 at 17:38