Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Say you went to PowerShell and added a path:

$env:path += 'C:\banal\cranial\inversion'

Oops, you forgot a ; in it, it should have been

$env:path += ';C:\banal\cranial\inversion'

-- but your path is already screwed up. In zsh, we can just vared PATH; what about PowerShell, is there a way to edit the variable instead of resetting it anew? And if resetting, how can you copy and paste just a part of it, if it wraps around?

share|improve this question
    
The zsh builtin is called vared rather than varedit. – Dennis Williamson Jan 22 '11 at 4:33
    
of course; context switching... fixed – Alexy Khrabrov Jan 22 '11 at 5:00
up vote 1 down vote accepted

It doesn't, but you could do something like:

    function Edit-Variable {
#.Parameter name
#    The name (or path) to the variable to edit.
#.Parameter Environment
#    Optional switch to force evaluating the name as an environment variable. You don't need this if you specify the path as env:Path instead of just "Path"
#.Example
#     Edit-Variable -env path
#.Example
#     Edit-Variable profile
#.Example
#     Edit-Variable env:\path
#.Example
#     Edit-Variable variable:profile

param(
    [Parameter(Position=0,ValueFromPipelineByPropertyName=$true,ValueFromPipeline=$true)]
    [string]$name
,
    [switch]$Environment
)
process {
    $path = Resolve-Path $name -ErrorAction SilentlyContinue
    if($Environment) {
        ## Force Env: if they said -Env
        if(!$path -or $Path.Provider.Name -ne "Environment") {
            $path = Resolve-Path "Env:$name"
        }
    } else {
        if($Path -and $Path.Provider.Name -eq "Environment") {
            $Environment = $true
        } elseif(!$path -or $Path.Provider.Name -ne "Variable") {
            $path = Resolve-Path "Variable:$name" -ErrorAction SilentlyContinue
        }
    }

    $temp = [IO.Path]::GetTempFileName()
    if($path) {
        if(!$Environment) {
            $value = (Get-Variable $path.ProviderPath).Value
            $string = $value -is [String]
            if(!$string) {
                Write-Warning "Variable $name is not a string variable, editing as CliXml"
                Export-Clixml $temp -InputObject $Value 
            } else {
                Set-Content $temp $Value
            }
        } else {
            Get-Content $path | Set-Content $temp
        }
    } else {
        $Environment = $false
        New-Variable $Name
        $path = Resolve-Path Variable:$name -ErrorAction SilentlyContinue
    }
    if(!$path) {
        Write-Error "Cannot find variable '$name' because it does not exist."
    } else {
        # Let the user edit it in notepad, and see if they save it
        $pre = Get-ChildItem $temp
        (Start-Process notepad $temp -passthru).WaitForExit()
        $post = Get-ChildItem $temp
        if($post.LastWriteTime -gt $pre.LastWriteTime) {
            if(!$Environment) {
                if(!$string) {
                    Import-CliXml $temp | Set-Variable $path.ProviderPath
                } else {
                    Get-Content $temp | Set-Variable $path.ProviderPath
                }
            } else {
                Get-Content $temp | Set-Content $path
            }
        }
    }
    Remove-Item $temp -ErrorAction SilentlyContinue
}
}

Set-Alias vared Edit-Variable

I know that's not how zsh's works, but notepad was handy...

share|improve this answer
    
Very interesting! Alas, pasting this into PS 2.0 and then saying, vared env:path causes a warning that it's not a string variable, editing as CliXml -- and then the notepad shows a <Nil /> wrapped in <Objs ...>. – Alexy Khrabrov Jan 22 '11 at 5:03
    
try vared -env path or vared path -env ... I made the env a switch: it works with environment variables, and regular variables (and anything else with content, really). I thought about requiring vared profile and vared env:path and just detecting the drive to see that it was env, but in the end, I went with the switch. I should have put an example in, I'll fix that. – Jaykul Jan 22 '11 at 6:08
    
OK, I totally redid the error handling, so now you can do either one you like: Edit-Variable env:path or Edit-Variable -env path – Jaykul Jan 22 '11 at 6:41

you could use the string methods to accomplish the correction

$indexError = $env:Path.LastIndexOf("C:")
$env:Path = $env:Path.remove($indexError, 1)
$env:Path = $env.Insert($indexError, ";C")

Don't forget that in powershell everything is an object, and you could use any programming strategies to achieve what you need.

share|improve this answer
    
this is very useful as well! as soon as I'm able I'll up it – Alexy Khrabrov Jan 26 '11 at 4:33
    
Yeah, it's totally true that you could handle this with simple script. Personally, I'd go for $Env:Path = $Env:Path -replace '(?<!;)C:',';C:' # replace C: that doesn't follow a ; with ';C:' – Jaykul Feb 2 '11 at 18:26
    
@jaykul very nice what you did, i wan't to learn more, what is the subject name to search further? – mjsr Feb 7 '11 at 17:42
    
It's a regular expression: specifically, that is a negative look-behind zero-width assertion. regular-expressions.info/lookaround.html – Jaykul Feb 8 '11 at 3:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .