【问题标题】:Find full path of a powershell script launched from an EXE wrapper查找从 EXE 包装器启动的 powershell 脚本的完整路径
【发布时间】:2016-11-08 21:44:05
【问题描述】:

我正在尝试创建一个 .exe 文件,它是一个打包的 powershell 脚本 (script.ps1),其中脚本的一部分是打印 .exe 文件的当前位置而不是脚本.

部分要求是 .exe 需要可移植:

所以当我运行 File.exe 或双击 File.exe 时:

如果文件的位置是 C:\Hello\File.exe ,它应该打印 "C:\Hello\"

如果位置移动到 D:\Goodbye\File.exe ,它应该打印 "D:\Goodbye\"

如果文件被复制到 D:\HELLO\File.exe ,它应该只打印 "D:\HELLO\"


我尝试过$PSScriptRoot,但它只链接到一个临时文件夹


在将 script.ps1 打包为 .exe 之前,我可以添加哪些代码使其查找 .exe 文件的特定位置?

谢谢

【问题讨论】:

  • 您如何创建可执行文件以及它如何运行 PowerShell 脚本?
  • 这可能是个坏主意。你说它必须是可移植的,但 PowerShell 在 .Net 框架上运行。如果您的目标机器没有 .Net,它就无法工作。如果它确实有 .Net,则不需要 .exe 包装器。自 Win 7/2008R2 以来的每个 Windows 版本都默认至少附带 PowerShell 2.0。您想通过将脚本打包成 .exe 来解决什么问题?
  • @briantist:好点,但我认为在这种情况下,OP 的“可移植”意味着仅仅能够将可执行文件放在 任何目录 中并让它工作正确。此工具生成的*.exe 包装器允许调用嵌入式 PowerShell 脚本,而不管有效的 PS 安全策略如何,因此提供一种更简单的方法来运行脚本可能是动机。
  • @mklement0 是的,但同样可以通过调用powershell.exe -ExecutionPolicy 的一行批处理文件来实现。
  • @AdilZia 实际上你可以查看mklement0's answer 中发布的示例包装器命令。这是对包装器在做什么的推测(调用powershell.exe)。相反,如果您在批处理文件中添加一行这样的行来调用您的.ps1,那么您可以在脚本中使用$PSScriptRoot。在批处理文件中,您可以使用%~f0\myScript.ps1 来引用与批处理文件相同路径的文件。

标签: windows powershell exe filepath


【解决方案1】:

您用来将 PowerShell 脚本包装在 *.exePs1 to Exe 中的工具在调用 *.exe 时执行以下操作:

  • 它将嵌入的脚本提取到子树$env:TEMP中的一个临时文件中。

  • 它调用 PowerShell 可执行文件,并通过-File-ExecutionPolicy Bypass 将临时脚本文件的路径传递给它。

包装器*.exe调用的示例命令行:

"powershell" -ExecutionPolicy Bypass -File C:\Users\jdoe\AppData\Local\Temp\2409.tmp\240A.ps1

因此,您需要检查运行脚本的 PowerShell 实例的 进程,以获取有关 包装器 *.exe 的信息。

# Get the parent process.
# (`gps` is a built-in alias of `Get-Process`)
$pp = gps -Id (Get-CimInstance win32_process -Filter "ProcessId = $PID").ParentProcessId

# Output the parent process executable's directory path:
Split-Path $pp.Path

注意:如果您仍在使用 PSv2,请使用 Get-WmiObject 而不是 Get-CimInstance

【讨论】:

  • 嘿,所以我的脚本在 exe 包内,我只做后半部分,还是顶部加后半部分?
  • 要么是一个,要么是另一个;根据您对乔纳森回答的评论,听起来 first sn-p 是您所需要的。
  • 谢谢,这也给了我运行exe时的临时文件夹lol
  • 我不确定你的意思。对不起。我是 Powershell 和系统方面的初学者。使用此工具f2ko.de/en/p2e.php将ps1编译为exe后我所做的一切...我只需双击或运行EXE文件
  • @AdilZia:请看我的更新,但我的建议没有改变:您需要从 parent 进程获取包装器可执行文件的目录路径。
【解决方案2】:

我从未使用过打包的 PowerShell 脚本,但如果 PowerShell 引擎由打包脚本的 EXE 托管,那么这样的事情应该可以解决问题:

$FullPathToEXE = [System.Diagnostics.Process]::GetCurrentProcess().MainModule.FileName

$DirectoryContainingEXE = [System.IO.Path]::GetDirectoryName($FullPathToEXE)

【讨论】:

  • 啊,糟了。 :-)
  • 在没有具体信息的情况下,值得一试 :) 请注意,您的命令的纯 PowerShell 翻译要简洁得多(尽管可能更慢):$DirectoryContainingExe = Split-Path (Get-Process -ID $PID).Path
  • 嗯,令人着迷。 PowerShell 的Get-Process 几乎直接返回System.Diagnostics.Process 对象,而Process 没有Path 属性。但是,%SystemRoot%\System32\WindowsPowerShell\v1.0 中的types.ps1xml 包含System.Diagnostics.Process 类型的特定映射,它添加了一大堆额外的“虚拟”属性。 Path 就是其中之一:<ScriptProperty> <Name>Path</Name> <GetScriptBlock>$this.Mainmodule.FileName</GetScriptBlock> </ScriptProperty>
  • 优秀的侦探。检查此属性的更直接方法是使用(Get-Process -id $PID) | Get-Member Path
  • @AdilZia PowerShell 是一种类似于 C# 或 VB.NET 的语言,它公开了 .NET 对象。但是,PowerShell 是为可扩展性而设计的。这种可扩展性的一部分是您实际上可以将新成员“添加”到类型中,通常是通过转发到另一个属性或让它们秘密执行一个 PowerShell 脚本块。作为这个 StackOverflow 问题的一部分,我了解到这一事实。因此,在这种情况下,当我看到您可以直接访问 Process 对象上的 .Path 时,我感到很惊讶——该对象没有具有名为 .Path 的属性。我开始弄清楚它是如何工作的。 :-)
猜你喜欢
  • 1970-01-01
  • 2012-01-15
  • 2016-01-27
  • 2020-10-13
  • 2011-11-01
  • 2020-02-05
  • 2021-10-31
  • 1970-01-01
  • 2014-11-18
相关资源
最近更新 更多