0

I've turned Chocolatey's uninstall script in to a one-line uninstall, which runs perfectly in Powershell, but doesn't work if I add it into a batch script.

Pasting this in Powershell Works

$VerbosePreference = 'Continue';if (-not $env:ChocolateyInstall) {$message=@("Chocolatey is not detected as installed. Nothing to do.") -join "`n";Write-Warning $message;return};if (-not (Test-Path $env:ChocolateyInstall)) {$message = @("No Chocolatey installation detected at '$env:ChocolateyInstall'. Nothing to do.") -join "`n";Write-Warning $message;return};$userKey=[Microsoft.Win32.Registry]::CurrentUser.OpenSubKey('Environment');$userPath=$userKey.GetValue('PATH', [string]::Empty, 'DoNotExpandEnvironmentNames').ToString();$machineKey=[Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SYSTEM\ControlSet001\Control\Session Manager\Environment\');$machinePath=$machineKey.GetValue('PATH', [string]::Empty, 'DoNotExpandEnvironmentNames').ToString();$backupPATHs=@("User PATH: $userPath","Machine PATH: $machinePath");$backupFile = "C:\PATH_backups_ChocolateyUninstall.txt";$backupPATHs | Set-Content -Path $backupFile -Encoding UTF8 -Force;$warningMessage = "This could cause issues after reboot where nothing is found if something goes wrong.In that case, look at the backup file for the original PATH values in '$backupFile'.";if ($userPath -like "*$env:ChocolateyInstall*") {Write-Verbose "Chocolatey Install location found in User Path. Removing...";Write-Warning $warningMessage;$newUserPATH = @($userPath -split [System.IO.Path]::PathSeparator | Where-Object { $_ -and $_ -ne "$env:ChocolateyInstall\bin" }) -join [System.IO.Path]::PathSeparator;$userKey.SetValue('PATH', $newUserPATH, 'ExpandString')};if ($machinePath -like "*$env:ChocolateyInstall*") {Write-Verbose "Chocolatey Install location found in Machine Path. Removing...";Write-Warning $warningMessage;$newMachinePATH = @($machinePath -split [System.IO.Path]::PathSeparator | Where-Object { $_ -and $_ -ne "$env:ChocolateyInstall\bin" }) -join [System.IO.Path]::PathSeparator;$machineKey.SetValue('PATH', $newMachinePATH, 'ExpandString')};$agentService = Get-Service -Name chocolatey-agent -ErrorAction SilentlyContinue;if ($agentService -and $agentService.Status -eq 'Running') {$agentService.Stop()};Remove-Item -Path $env:ChocolateyInstall -Recurse -Force;'ChocolateyInstall', 'ChocolateyLastPathUpdate' | ForEach-Object {foreach ($scope in 'User', 'Machine') {[Environment]::SetEnvironmentVariable($_, [string]::Empty, $scope)}};$machineKey.Close();$userKey.Close();if ($env:ChocolateyToolsLocation -and (Test-Path $env:ChocolateyToolsLocation)) {Remove-Item -Path $env:ChocolateyToolsLocation -Recurse -Force};foreach ($scope in 'User', 'Machine') {[Environment]::SetEnvironmentVariable('ChocolateyToolsLocation', [string]::Empty, $scope)};pause

However if I add it in a batch script starting with

start powershell.exe -Command "Powershell script I posted above" it doesn't work.

  • 1
    If you want to make your life easier and you really, really want to run this from CMD, you can opt to use `powershell -File path/to/script.ps1` or you can b64 encode your oneliner and then pass the b64 encoded string to `powershell -EncodedCommand ...` – Santiago Squarzon Mar 24 '22 at 20:28
  • 1
    If you want to know one of the reasons it fails is because your entire `-Command` is correctly double-quoted, which means that every nested double-quote requires to be escaped for the cmd.exe executable. You would do that by prefixing all of those in your working PowerShell command line with a backward slash. – Compo Mar 24 '22 at 20:58
  • Thanks for the suggestion, but I want to make it a "one file" to easily send to my friends. I found the problem. The powershell command only works in Powershell v5, but 'start powershell -command' opens the v1.0 version in cmd. Anyone knows how to change it? – Lam Ken_ Mar 24 '22 at 21:02
  • Are you sure it is v1.0? There is no PowerShell 1.0 on recent Win OS. Its path contains "1.0" only for backwards compatibility. Type `$PSVersionTable` to be sure. – zett42 Mar 24 '22 at 21:22
  • It doesn't, the location `%SystemRoot%\System32\WindowsPowerShell\v1.0` is the parent path for the installed powershell.exe up to v5.1, on supported Windows Operating Systems. `%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -Command "$PSVersionTable"`, should clarify that. You could even get the major number like this: `%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoLogo -NoProfile -Command "$(($PSVersionTable).PSVersion).Major"`. Also there is a powershell option change the version too, `%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -Version 2.0`. – Compo Mar 24 '22 at 21:25
  • In short: When calling PowerShell's _CLI_ (`powershell.exe` for _Windows PowerShell_, `pwsh` for _PowerShell (Core) 7+_) from the outside, using `-Command` / `-c`, you need to _escape_ `"` chars. you want passed through as part of the command: `\"` works in principle, but can break when calling from `cmd.exe`. In that case, use `"^""` (sic) with `powershell.exe`, and `""` with `pwsh.exe`, inside overall `"..."` quoting.. See the linked duplicate for details. – mklement0 Mar 24 '22 at 21:30
  • Try to put the value of your script block enclosed with { curly parentheses } `Powershell.exe -Command "&{Powershell script you posted}"` – Christophe Mar 24 '22 at 22:42
  • @LamKen_ If you use line separators (`;`) in a "one-liner", then basically every PowerShell script can be a one-liner. The challenge in nice one-liners is to make them readable in one line (without a 50" monitor). But that's off-topic (feel free to flag as NLN). – stackprotector Mar 25 '22 at 06:59

0 Answers0