简体   繁体   English

重命名文件脚本-如何将当前目录用于上下文菜单

[英]rename files script - how to use current directory for context menu

I have the following script with the line below pulling a context/browse menu for the users to easily navigate to a file of their choice and rename a file. 我有以下脚本,下面的一行拉出上下文/浏览菜单,以便用户轻松导航到他们选择的文件并重命名文件。 Instead of using a static location for the directory, how can I grab the current directory that the script is launched from, or current directory? 而不是使用静态位置作为目录,如何获取启动脚本的当前目录或当前目录?

EDIT: I forgot to mention I also want to be able to rename each file individually(prompt user for each file in the folder selected) instead of renaming every file the same thing. 编辑:我忘了提一提,我也希望能够单独重命名每个文件(提示用户选择文件夹中每个文件),而不是将每个文件重命名为相同的东西。

FYI: I use a .bat file to fire up this powershell script. 仅供参考:我使用.bat文件启动此Powershell脚本。

##########################################################################
#Functions
##########################################################################

# Show input box popup and return the value entered by the user.
function Read-InputBoxDialog([string]$Message, [string]$WindowTitle, [string]$DefaultText)
{
Add-Type -AssemblyName Microsoft.VisualBasic
return [Microsoft.VisualBasic.Interaction]::InputBox($Message, $WindowTitle, $DefaultText)
}

# Show an Open Folder Dialog and return the directory selected by the user.
function Read-FolderBrowserDialog([string]$Message, 
[string]$InitialDirectory, [switch]$NoNewFolderButton)
{
$browseForFolderOptions = 0
if ($NoNewFolderButton) { $browseForFolderOptions += 512 }

$app = New-Object -ComObject Shell.Application
$folder = $app.BrowseForFolder(0, $Message, $browseForFolderOptions, $InitialDirectory)
if ($folder) { $selectedDirectory = $folder.Self.Path } else { $selectedDirectory = '' }
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($app) > $null
return $selectedDirectory
}

##########################################################################
#Start Code
##########################################################################

$i = 1

$directoryPath = Read-FolderBrowserDialog -Message "Please select a directory" -NoNewFolderButton -InitialDirectory 'P:\'
if (![string]::IsNullOrEmpty($directoryPath)) { Write-Host "You selected the directory: $directoryPath" }
else { "You did not select a directory." }



$acctdol = Read-InputBoxDialog -Message "Please enter the Account_DOL" -WindowTitle "Account_DateOfLoan" -DefaultText "########_MMDDYYYY_XXX"
if ($acctdol -eq $null) { Write-Host "You clicked Cancel" }
#elseif ($acctdol -eq "Something") { Write-Host "Thanks for typing Something" }
else { Write-Host "You entered $acctdol" }

If(!$acctdol){
$isnull++
}
else{
Get-ChildItem -Path $($directoryPath)*.pdf -Recurse -Force | 
ForEach-Object {
$newname = "${acctdol}_{0}.pdf" -f $i 
$i++
Rename-Item -Path $_.FullName -NewName $newname
}
}


##########################################################################
#Closing
##########################################################################
if ($Host.Name -eq "ConsoleHost")
{ 
Write-Host "Press any key to continue..."
$Host.UI.RawUI.FlushInputBuffer()   # Make sure buffered input doesn't "press a key" and skip the ReadKey().
$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp") > $null
}

You do not specify if the PS script is in the same location as the batch file, so I'm not going to assume that it is and treat this like the path to the script is hard coded into the batch file, and that the batch file could be anywhere on the machine. 您无需指定PS脚本是否与批处理文件位于相同的位置,因此我不会假定它与脚本文件的路径一样被硬编码到批处理文件中,并且不会将该批处理视为批处理文件文件可以在计算机上的任何位置。

As Squashman points out, %~dp0 is the current path in the batch file. 正如Squashman指出的那样, %~dp0是批处理文件中的当前路径。 What I would do is create a parameter in the PS script that accepts a path, and then pass the current path for the batch file to the PS script when you call it. 我要做的是在PS脚本中创建一个接受路径的参数,然后在调用它时将批处理文件的当前路径传递给PS脚本。 So start the script off like: 因此,像这样启动脚本:

[cmdletBinding()]
Param(
    [string]$CallingPath
)

Then you can refer to that for your BrowseForFolder call if you want. 然后,您可以根据需要在BrowseForFolder调用中引用该名称。 In the batch file you would call it like: 在批处理文件中,您可以这样称呼它:

%windir%\system32\windowspowershell\v1.0\powershell.exe -file c:\Path\To\script.ps1 '%~dp0'

Edit: As for naming each file, I'm guessing that giving the user the option to name the files sequentially or name each file would be a good idea, then if they choose to name each one prompt for each file. 编辑:至于命名每个文件,我猜想让用户选择按顺序命名文件或命名每个文件是一个好主意,然后,如果他们选择为每个文件命名一个提示。 For asking their preference I like the Windows.Forms.MessageBox, for which I have this function that I toss into the beginning of scripts that need it: 为了询问他们的喜好,我喜欢Windows.Forms.MessageBox,为此,我提供了此函数,并将其扔入需要它的脚本的开头:

Function Show-MsgBox ($Text,$Title="",[Windows.Forms.MessageBoxButtons]$Button = "OK",[Windows.Forms.MessageBoxIcon]$Icon="Information"){
[Windows.Forms.MessageBox]::Show("$Text", "$Title", [Windows.Forms.MessageBoxButtons]::$Button, $Icon) | ?{(!($_ -eq "OK"))}
}

Then you can just do: 然后,您可以执行以下操作:

$NameEach = Show-MsgBox -Text "Do you want to rename each file sequentially based on the Account_DOL?`nIf you select No you will be prompted for a name for each file." -Title "Auto-Rename?" -Button YesNo -Icon Question

If you're writing this in the ISE it'll pop up options for what buttons and icons are available for you to select, or tab complete works for both the ISE and console. 如果您在ISE中编写此代码,它将弹出选项供您选择可供选择的按钮和图标,或者在ISE和控制台上都使用完整的选项卡。

Then for naming files I would use the Windows.Forms.SaveFileDialog window (I like using the Windows.Forms dialogs because they're familiar to people). 然后,为了命名文件,我将使用Windows.Forms.SaveFileDialog窗口(我喜欢使用Windows.Forms对话框,因为它们是人们所熟悉的)。 Here's a function for that: 这是一个函数:

Function Get-OutputFilePath{
[CmdletBinding()]
Param(
    [String]$Filter = "All Files (*.*)|*.*",
    [String]$InitialDirectory,
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [Alias('DefaultFileName')]
    [String]$FullName,
    [Switch]$Force)
    BEGIN{
        [void][System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
    }
    PROCESS{
        If($FullName -match "\\.+$" -and !$InitialDirectory){$InitialDirectory = Split-Path $FullName;$FullName = Split-Path $FullName -Leaf}ElseIf(!$InitialDirectory){$InitialDirectory=[Environment]::GetFolderPath('Desktop')}
        $SaveFileDialog = New-Object System.Windows.Forms.SaveFileDialog
        $SaveFileDialog.initialDirectory = $InitialDirectory
        Try{$SaveFileDialog.filter = $Filter}Catch{Throw $_;Break}
        $SaveFileDialog.FileName = $FullName
        $SaveFileDialog.OverwritePrompt = !$Force
        If($SaveFileDialog.ShowDialog() -eq "OK"){$SaveFileDialog.FileName}
    }
}

It looks worse than it is, really. 看起来确实比实际更糟。 But with that included in your functions you can do this in your ForEach loop when you're cycling through file to rename them: 但是,有了函数中包​​含的功能,当您循环遍历文件以重命名它们时,可以在ForEach循环中执行此操作:

$newname = If($NameEach -eq 'Yes'){$_|Get-OutputFilePath -Filter 'PDF File (*.pdf)|*.pdf|All Files (*.*)|*.*'|Split-Path -Leaf}Else{"${acctdol}_{0}.pdf" -f $i}
If($_.Name -ne $newname){$_|Rename-Item -NewName $newname}

That will prompt them with a Save File dialog defaulting to the correct directory, and name for the current file, and then set the $newname variable to whatever they select. 这将提示他们默认情况下为正确目录的“保存文件”对话框,并为当前文件命名,然后将$newname变量设置为所选内容。 Plus it does some things that are handy like prompting if they want to overwrite files, validating file names and paths, and stuff like that. 另外,它还能执行一些方便的操作,例如提示他们是否要覆盖文件,验证文件名和路径以及类似的东西。 Last thing I did was make sure they specified a new name so that we don't get errors trying to rename a file to the exact same thing. 我做的最后一件事是确保他们指定了一个新名称,以便在尝试将文件重命名为完全相同的名称时不会出错。

Bonus function! 奖励功能! I notice that you pause at the end of the script, so I wanted to pass along the function I use to pause since it doesn't fail in the ISE, and allows you to pass a message to it to display. 我注意到您在脚本末尾暂停了,所以我想传递用于暂停的功能,因为它在ISE中不会失败,并允许您向其传递消息以显示。 In the ISE it pops up a dialog box with the message and an OK button, in the console it displays the message and a 'Press any key to continue...' message, much like yours does. 在ISE中,它会弹出一个带有消息和“确定”按钮的对话框,在控制台中,它会显示消息和“按任意键继续...”消息,就像您的消息一样。 For your script I'm sure what you have works perfectly, I just wanted to share. 对于您的脚本,我确定您的工作完美,我只是想分享一下。

Function Invoke-Pause ($Text){
    If($psISE){
        [Windows.Forms.MessageBox]::Show("$Text", "Script Paused", [Windows.Forms.MessageBoxButtons]"OK", [Windows.Forms.MessageBoxIcon]"Information") | ?{(!($_ -eq "OK"))}
    }Else{
        Write-Host $Text
        Write-Host "Press any key to continue ..."
        $Host.UI.RawUI.FlushInputBuffer()
        $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM