65.9K
CodeProject 正在变化。 阅读更多。
Home

PowerShell 中的类 Bash 提示符和应用程序运行

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2011年7月11日

GPL3

3分钟阅读

viewsIcon

24170

downloadIcon

137

一篇文章,描述了PowerShell脚本和配置文件的技巧,可以让你在PowerShell中获得类似Bash的提示符,并更灵活地运行应用程序。

Sample Image

引言

在批处理脚本中,编写代码来完成简单的事情非常繁琐。PowerShell 让我们更容易地完成这些事情,并且它在访问和控制系统资源方面也表现出色,因为它使用了 .NET Framework。我不得不提到一些我编写过的并且很有用的代码片段。

背景

当我从 Unix/Linux 迁移到 PowerShell 时,我很想念 Bash 提示符。Bash 提示符不会显示整个目录路径,并且有一个家目录符号。这保持了终端的整洁。出于安全原因,PowerShell 施加了许多限制。例如,你有一个脚本 delay.ps1。即使启用了执行策略,你也不能通过输入 delay 来运行它。我决定使用前缀 ss 来运行所有这些程序。现在,有了提供的脚本,我们可以输入 ss scriptname 来简单地运行一个脚本(即使我们省略了扩展名或 .\ 也可以)。

使用代码

将文件 Microsoft.PowerShell_profile.ps1 的代码放入你的配置文件中,并将 ss.ps1 放在你想要存放脚本的位置。

你需要启用你的电脑上的 PowerShell 脚本执行策略。要为当前用户启用它,你可以运行 PS > set-executionpolicy Unrestricted -scope currentuser

脚本内部

如果想在 Windows PowerShell 中使用类似 Unix 的提示符,我们使用以下代码,其中包含两个函数,promptget-diraliasget-diralias 函数在遇到我们设置的家目录时(这里是 E:\Scripts),会返回一个重音符号。

如果不是家目录,那么我们找到一个反斜杠 (\)。仅获取该斜杠后的最后一部分作为子字符串。否则,如果我们发现当前位置字符串以 \ 结尾,我们就知道我们在驱动器的根目录下。在这种情况下,我们只返回驱动器和冒号。

$env:homedir=E:\Scripts
# get the last part of path
function get-diralias ([string]$loc) {
    # check if we are in our home script dir
    # in that case return grave sign
    if ($loc.Equals($env:homedir)) {
        return "~"
    }
    
    # if it ends with \ that means we are in root of drive
    # in that case return drive
    $lastindex = [int] $loc.lastindexof("\")
    if ($loc.EndsWith("\")) {
        return $loc.Remove($lastindex, 1)
    }
    
    # Otherwise return only the dir name
    $lastindex += 1
    $loc = $loc.Substring($lastindex)
    return $loc
}

# Set prompt
function prompt {
    return "[sa@matrix $(get-diralias($(get-location)))]$ "
}

我们添加了另一个函数 ss,它提供以下功能

# To go home
$ ss cd

# To edit powershell profile script
$ ss ep

# To open a text/script file with Powershell ISE 
$ ss ise filename.ps1

# List programs which are available in app path that can be run
# with simply putting with ss i.e., ss notepad++ or ss chrome
$ ss list-programs

# run a program from apppath, app path in registry
# is a collection of paths when you run a command
# from run dialog box it looks for executable file paths
# there (correct me if I am wrong)
$ ss chrome
Or
$ ss devenv

ss 是一个命令,如果提供的文件路径不存在,它将创建该文件。让我们进入脚本。我们拥有教父函数 ss,它以适当的方式管理命令行参数,如果没有提供命令行参数则发出警告,并使用这些参数调用 ss.ps1 脚本。我这样做是为了保持配置文件更小。

function ss() {
    if ($args.Count -lt 1) {
        return "Please provide correct commandline"
    }
    elseif ($args.Count -eq 1) {
        & "$env:homedir\ss.ps1" $args
    }
    else {
        $cmd = $args[0]
        # echo "cmd: `"$cmd`""
        $cargs = [string]$args
        # echo "cargs: `"$cargs`""
        $cargs = $cargs.TrimStart($cmd)
        $cargs = $cargs.TrimStart()
        # echo "cargs: `"$cargs`""
        & "$env:homedir\ss.ps1" $args[0] $cargs
    }
    
    return ""
}

ss cdss ep 的功能很容易理解。最初,ss ise 的代码更简单。但是 ise 有时表现不稳定。这就是为什么我将命令行更正为指定绝对文件路径而不是相对路径,即 .\filename.ext 是相对路径,而 e:\folder\filename.ext 是绝对文件路径。

# ss ise: call powershell_ise editor
if ($cmd.ToLower().Equals("ise")) {
    $cargs = [string]$args[1]

    $cpath = $cargs
    # if the file 
    if ($cargs.IndexOf("\") -eq "-1") {
        $cpath =$(get-location).path+"\$cargs"
    }
    elseif ($cargs.StartsWith("..\")) {
        $cpath =$(get-location).path
        $cpath =$cpath.Substring(0, $cpath.LastIndexOf("\"))
        $cpath +=$cargs.TrimStart("..")
    } 
    elseif ($cargs.StartsWith(".\")) {
        $cpath =$(get-location).path+$cargs.TrimStart(".")
    }
    
    if (Test-Path $cpath) {
        # echo "1. Path: $cpath"
        & $env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell_ise.exe $cpath
    }
    else {
        echo "Creating File $cpath as it does not exist."
        echo "# Date: $(get-date)"> $cpath
        echo "# Author: $env:USERNAME">> $cpath
        & $env:SystemRoot\system32\WindowsPowerShell\v1.0\powershell_ise.exe $cpath
    }
    break
}

要从应用程序路径运行程序,ss 首先会检查以下注册表项是否存在:HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\$(cmdArgument).exe。如果找到它,它将获取该键的默认值,即可执行文件的文件路径。我们删除两端引号。

if (Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\$cmd.exe") {
        echo "Starting program $origcmd"
    $regitem = Get-ItemProperty 
       "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\$cmd.exe"
    # Get-ItemProperty 
       "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\notepad++.exe"
    $regcmd = $regitem."(default)"
    # Modify the command so that arguments don't get splitted
    $regcmd = $regcmd.TrimStart("`"")
    $regcmd = $regcmd.TrimEnd("`"")
    & "$regcmd" $cargs
    break
}
elseif (!(Test-Path "$env:homedir\$cmd.ps1")) {
    echo "Please check your command"
    break
}

希望这些脚本能帮助你自动化你的工作。谢谢。

历史

  • 初始发布 - 2011 年 7 月 11 日。
© . All rights reserved.