Peeter Joot's (OLD) Blog.

Math, physics, perl, and programming obscurity.

More windows powershell play

Posted by peeterjoot on December 26, 2010

It’s been a while since I tried windows powershell. I have a new Windows 7 computer now, and it seemed like a good opportunity to try it again. This shell is very different than the old windows shell, and it takes getting used to. My first task today was to figure out how to modify, or even see an environment variable. It turns out that this has a unix like syntax, so for example, I’m able to do the following:

echo $env:PATH
echo $env:HOMEPATH

Okay, perhaps I can make a unix like ‘cd’ alias that takes me straight to my %HOMEPATH%. I try the following (long winded) alias like command:

new-item -path alias:homedir -value 'cd $env:homepath'

Does it work?

PS C:\Users\Peeter\bin> homedir
Cannot resolve alias 'homedir' because it refers to term 'cd $env:homepath', which is not recognized as a cmdlet, funct
ion, operable program, or script file. Verify the term and try again.
At line:1 char:8

Nope. Perhaps I need chdir instead of cd. A bit of blundering and I find that I can remove my alias and try again with:

Remove-Item -path alias:homedir
new-item -path alias:homedir -value 'chdir $env:homepath'

But this behaves no better. I seem to recall that ‘cd’ and ‘chdir’ were in fact aliases in powershell, so I probably need the real applet names that these resolve to.

I recall that I’d made a note about how to save and restore aliases, and how to see what all the aliases were, but I get sidetracked, and wonder if I can make an aliases script, but I’m in a bit of a chicken and egg bind since I can’t start up a decent (ie: vim) editor. How do I modify my path?

It appears that I can do this also unix style with, in this case:

$env:PATH = "$env:PATH;C:\Program Files (x86)\Vim\vim73"

I don’t want to type this again, so it’s time to see if I can make a setenv.ps1 powershell script to perform this task. I produce such a file and get a message that scripts are disabled, with info on how to digitally sign scripts to allow execution, or how to change execution privledges to only block remote shell scripts. The command to do that appears to be:

Set-ExecutionPolicy RemoteSigned

but you have to start your powershell script in admin mode to do so. Under the powershell menu in the Start Menu (once I pin the command there), I have an admin mode prompt and am able to do so.

Rather painful, but I’m now able to create a basic powershell script, to import some useful environment settings. I found that this can be done in a multi-line fashion using back-quote as a line continuation character:

PS C:\Users\Peeter\bin> type .\setenv.ps1
$env:PATH = "$env:PATH" `
+ ";C:\Program Files (x86)\Vim\vim73" `
+ ";C:\cygwin\bin" `
+ ";C:\Program Files\Microsoft SDKs\Windows\v7.0\Bin\x64"

Now that I can run a script, here’s my aliases script:

get-item -path alias:* | where-object {$_.Definition -eq "Get-Childitem"}

I see that I have an alias for Get-Childitem, and can in fact use that to see my aliases:

PS C:\Users\Peeter\bin> gci alias:* | grep chdir
Alias           chdir                                               Set-Location

It also appears that I can use alias for this. Now can I make an alias that changes my home directory?

If I put this in a .ps1 script, and try to execute it, it appears that the scope of the new-item is restricted to the execution of the .ps1 script, as the following illustrates:

PS C:\Users\Peeter\bin> type .\alias1.ps1
new-item -path alias:homedir -value 'Set-Location $env:homepath'
PS C:\Users\Peeter\bin> .\alias1.ps1

CommandType     Name                                                Definition
-----------     ----                                                ----------
Alias           homedir                                             Set-Location $env:homepath


PS C:\Users\Peeter\bin> homedir
The term 'homedir' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spe
lling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:8
+ homedir <<< get-item -path alias:homedir
Get-Item : Cannot find path 'Alias:\homedir' because it does not exist.
At line:1 char:9
+ get-item <<<<  -path alias:homedir
    + CategoryInfo          : ObjectNotFound: (Alias:\homedir:String) [Get-Item], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand

But, if I do it on the command line directly, I still have no luck:

PS C:\Users\Peeter\bin> new-item -path alias:homedir -value 'Set-Location $env:homepath'

CommandType     Name                                                Definition
-----------     ----                                                ----------
Alias           homedir                                             Set-Location $env:homepath


PS C:\Users\Peeter\bin> homedir
Cannot resolve alias 'homedir' because it refers to term 'Set-Location $env:homepath', which is not recognized as a cmd
let, function, operable program, or script file. Verify the term and try again.
At line:1 char:8
+ homedir <<<<
    + CategoryInfo          : ObjectNotFound: (homedir:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : AliasNotResolvedException

Perhaps this is a quoting issue? Maybe no quotes, or double quotes? No quotes doesn’t work:

PS C:\Users\Peeter\bin> gci alias:homedir

CommandType     Name                                                Definition
-----------     ----                                                ----------
Alias           homedir                                             Set-Location $env:homepath


PS C:\Users\Peeter\bin> remove-item -path alias:homedir
PS C:\Users\Peeter\bin> new-item -path alias:homedir -value Set-Location $env:HOMEPATH
New-Item : A positional parameter cannot be found that accepts argument '\Users\Peeter'.
At line:1 char:9
+ new-item <<<<  -path alias:homedir -value Set-Location $env:HOMEPATH
    + CategoryInfo          : InvalidArgument: (:) [New-Item], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.NewItemCommand

How about double quotes?

PS C:\Users\Peeter\bin> new-item -path alias:homedir -value "Set-Location $env:homepath"

CommandType     Name                                                Definition
-----------     ----                                                ----------
Alias           homedir                                             Set-Location \Users\Peeter


PS C:\Users\Peeter\bin> homedir
Cannot resolve alias 'homedir' because it refers to term 'Set-Location \Users\Peeter', which is not recognized as a cmd
let, function, operable program, or script file. Verify the term and try again.
At line:1 char:8
+ homedir <<<<
    + CategoryInfo          : ObjectNotFound: (homedir:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : AliasNotResolvedException

Nope.

Perhaps I need multiple parameter aliases have to be specified differently?

The help alias powershell info shows a similar example, but they use a function to do it. Let’s try that:

PS C:\Users\Peeter\bin> function homedir {set-location -path $env:HOMEPATH}
PS C:\Users\Peeter\bin> homedir
PS C:\Users\Peeter> 

Okay. I can live with that. Use functions instead of aliases. I do that in bash too sometimes, and it’s not too much of an imposition to do that for simple “aliases” in powershell. Now I just want an easy way of repeating this, and see that this is possible with a powershell profile script.

The $profile variable had the path to the script:

PS C:\Users\Peeter\bin> echo $profile
C:\Users\Peeter\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

I’d seen this earlier when I was figuring out how to change environment variables. The variable is set, although the path (including the directory leading up to it) didn’t actually exist. Once I created that directory, and the file, it also didn’t execute because of the permissions issue. Now that I’ve set permissions to only exclude Remote scripts, it does work, and I can put my “alias” there.

Wow, that sidetracked me a bit! I started out with the intention to try to get an opengl sample program compiling with the Windows SDK compiler, and it appears that I cannot even do that in a powershell environment. There’s no equivalent to SetEnv.Cmd for powershell in the Windows SDK!

Advertisements

4 Responses to “More windows powershell play”

  1. Jeffrey Snover (MSFT) said

    There are a number of good reasons why our parser works the way it does but right now aliasing only works for tokens – they can only expand to a command name. We would like to address that in a future release but until then, functions are the only way to do this. Bruce Payettes book PowerShell In Action details the reasons behind our language choices if you are interesested in the details..

    Cheers!

    • peeterjoot said

      Interesting that this would have been on purpose, given the behavior of any unix shell. That`s a book I`d be curious to look at for a while if I ever encountered it at the library (as a casual user, with cygnus bash and perl also available for Windows I don`t truly know how much time I`ll end up investing in learning this new shell, so I`ll not likely buy it).

  2. Jeffrey Snover said

    Short version:

    The traditional Unix shell parsing rules are open to SQL Injection type attacks that we attempted to studiously avoid. We have one cmdlet where this is possible and we try to discourage it’s use for this very reason (Invoke-Expression). Image you do something like:

    PS> Invoke-Expression “Get-Process -Name $(Read-Host -Prompt “ProcessName”)”
    ProcessName: lsass

    Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
    ——- —— —– —– —– —— — ———–
    1509 35 10448 21388 56 75.29 628 lsass

    PS> Invoke-Expression “Get-Process -Name $(Read-Host -Prompt “ProcessName”)”
    ProcessName: lsass ; Write-Host ‘**** I OWN THIS MACHINE ****’

    Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
    ——- —— —– —– —– —— — ———–
    1504 35 10448 21388 56 75.29 628 lsass
    **** I OWN THIS MACHINE ****

    Now imagine you try this more normally:

    PS> Get-Process -Name $(Read-Host -Prompt “ProcessName”)
    ProcessName: lsass

    Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
    ——- —— —– —– —– —— — ———–
    1491 35 10360 21308 56 75.29 628 lsass

    PS> Get-Process -Name $(Read-Host -Prompt “ProcessName”)
    ProcessName: lsass ; Write-Host ‘**** I OWN THIS MACHINE ****’
    PS>
    # You didn’t get any processes because the entire line was bound to the parameter and there is no process whose name is “lsass ; Write-Host ‘**** I OWN THIS MACHINE ****'”

    We are super super cautious about security and safety.

    Enjoy!

    Jeffrey Snover [MSFT]
    Distinguished Engineer
    Visit the Windows PowerShell Team blog at: http://blogs.msdn.com/PowerShell
    Visit the Windows PowerShell ScriptCenter at: http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: