如何只允许通过脚本而不是终端 wt.exe (PowerShell) 运行函数

How can I only allow a function to be run via a script and not the terminal wt.exe (PowerShell)

提问人:Alexander 提问时间:8/10/2023 最后编辑:mklement0Alexander 更新时间:8/11/2023 访问量:52

问:

几个小时以来,我一直在尝试制作一个函数,使其仅在由脚本而不是终端运行时才运行。

我有一个 Profile.ps1,它在每个终端实例上运行。就像 linux .bashrc 文件一样。C:\Users\Alexander\Documents\PowerShell\Profile.ps1

在我的文件中,我有这个。Profile.ps1

# Get PowerShell Profile Path
$pwsh = [System.Environment]::GetFolderPath("MyDocuments") + "\powershell"

# Dot source the internal functions I only want to be able to access via script and not terminal.
. $pwsh\internal\funcs.ps1

在文件中,我有这个。$pwsh\internal\funcs.ps1

function MyPrivateFunction {
    Write-Host "Hello"
}

我试过使用,它按预期工作。$MyInvocation.CommandOrigin

function MyPrivateFunction {
    if ($MyInvocation.CommandOrigin -eq "Runspace") {
        return
    }
    Write-Host "Hello"
}

当我启动一个新终端时,字符串会写入屏幕。"Hello"

如果我像这样调用命令 MyPrivateFunction:它有效并且不返回任何内容。PS C:\Users\Alexander> MyPrivateFunction

但是我遇到的问题是我不想在所有函数中编写if语句。

这将是大量的代码重复,而且一点也不好。

如果我在以下位置制作这样的函数:funcs.ps1

function Get-Origin {
    if ($MyInvocation.CommandOrigin -eq "Runspace") {
        Exit
    }
}

function MyPrivateFunction {
    Get-Origin
    Write-Host "Hello"
}

这是行不通的。因为当我调用它时,它会返回,因为它被函数调用。MyPrivateFunctionInternalMyPrivateFunction

因此,即使您直接在终端中键入 MyPrivateFunction,它仍将被视为 并且仍然打印 。internal"Hello"

而且我只希望它由脚本运行时运行。

有点像蟒蛇:.python if __name__ == __main__

我也尝试过使用 .psm1 模块,但它仍然会打印.Hello

我尝试使用 a 导入函数,但由于我猜在相同的范围内,它仍然会打印。.psm1 moduleHello

我唯一的解决方案是在每个函数上编写 但是由于大量代码重复,我认为这不是一个可行的选择。if ($MyInvocation.CommandOrigin -eq "Runspace")

一定有比这更好的东西。

我也认为这个问题是独一无二的,以前没有被问过。因为我已经搜索并尝试了要使用的答案,但它没有按照我想要的方式运行。PowerShell modules

我希望它只允许在脚本中运行,而不是通过powershell终端。MyPrivateFunction

由于使用点源文件,它就在那里。funcs.ps1

一种可能可行的方法是运行 python 脚本并在那里执行所有操作,但这将是另一个过程。

PowerShell Shell 终端 范围 Windows-Terminal

评论

0赞 Santiago Squarzon 8/10/2023
这有帮助吗?stackoverflow.com/a/75251803/15339544
0赞 Alexander 8/10/2023
如果我在每个功能上都使用它,是的。但是我不能把它写成一个函数,因为它仍然会打印“Hello”。因此,我需要在 funcs.ps1 中编写的每个函数上设置 if 语句,我无法将 if 语句写入函数并使用该函数,因此我需要将 if 语句放入 funcs.ps1 中的每个函数中。
0赞 Alexander 8/10/2023
但我想我可以在每个函数中编写 if 语句,我现在找不到另一种可能的方法。
0赞 zett42 8/10/2023
您是否尝试过将模块与?所有列出的函数都将是私有函数,不能在模块外部调用。Export-ModuleMember -Function 'PublicFunction1','PublicFunction2', ...

答:

0赞 TheMadTechnician 8/10/2023 #1

如果您不介意丢失 Tab 自动补全(这应该无关紧要,因为您不应该以交互方式运行函数),一种可能的解决方案是使用一个调用函数脚本的脚本,执行所需的函数,但前提是它通过脚本运行。

funcs.ps1:

Param(
    [parameter(Position=0)]$FunctionName,
    [parameter(Position=1,ValueFromRemainingArguments= $true)]$FunctionArgs
)
. $pwsh\internal\subfuncs.ps1
if($MyInvocation.CommandOrigin -eq "Runspace"){Write-Warning 'Cannot be run interactively';return}
&$FunctionName @FunctionArgs

然后将所有函数移动到 subfuncs.ps1 中。然后,您可以在个人资料中将其称为:

$pwsh\internal\funcs.ps1 MyPrivateFunction

或者,如果您不喜欢按名称调用脚本,则可以创建一个函数来调用它,并对调用者函数进行门禁:

Function Call-Function{
    if($MyInvocation.CommandOrigin -eq "Runspace"){
        Write-Warning 'Cannot be run interactively'
        return
    }
    & $pwsh\internal\funcs.ps1 @args
}

然后在你的脚本中只是 ,或者如果太长,将函数名称减少到 or 其他什么,它只是 .Call-Function myprivatefunctioncfcf myprivatefunction

评论

0赞 Alexander 8/10/2023
如何为此使用别名?比如:Set-Alias -Name sayhello -Value Call-Function myprivatefunction?找不到接受参数“myprivatefunction”的位置参数。
0赞 Alexander 8/10/2023 #2

我终于做到了!包括使用别名。

C:\Users\Alexander\Documents\PowerShell
├── Profile.ps1
├── internal
│   ├── funcs.ps1
│   └── subfuncs.ps1
└── powershell.config.json

Profile.ps1:

$pwsh = [System.Environment]::GetFolderPath("MyDocuments") + "\powershell"

function Open-Function{
    if($MyInvocation.CommandOrigin -eq "Runspace"){
        Write-Warning 'Cannot be run interactively'
        return
    }
    & $pwsh\internal\funcs.ps1 @args
}

function New-Ln-Link {
    Open-Function "New-SymbolicLink"  @args
}

function New-Admin-Right {
    Open-Function "Update-Rights"
}

function New-Wtd {
    param (
        [string[]]$Arguments
    )

    $targetPath = Join-Path (Get-Location) ($Arguments -join " ")

    # Assuming Open-Function is a custom command to call functions dynamically
    Open-Function "Start-WindowsTerminalInDirectory" $targetPath
}

New-Alias -Name ln -Value New-Ln-Link @args
New-Alias -Name admin -Value New-Admin-Right
New-Alias -Name wtd -Value New-Wtd

subfuncs.ps1:

function Update-Rights {
    if(!([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) {
        $workingDirectory = Get-Location
        Write-Host $MyInvocation.MyCommand.UnboundArguments
        Start-Process -FilePath wt.exe -Verb Runas -ArgumentList "-d `"$($workingDirectory)`" `"$($MyInvocation.MyCommand.UnboundArguments)`""

        Exit
    }
}
function Start-WindowsTerminalInDirectory {
    param (
        [string]$Directory = (Get-Location)
    )
    
    Start-Process -FilePath "wt.exe" -ArgumentList "-d $Directory"
}




function New-SymbolicLink {
    param(
        [string]$Source = (Get-Location).Path,
        [string]$Target
    )

    if (-not $Source) {
        Write-Error "Please provide a valid source path."
        return
    }

    if (-not $Target) {
        Write-Error "Please provide a valid target path."
        return
    }

    $Source = Join-Path (Get-Location).Path $Source

    New-Item -Path $Target -ItemType SymbolicLink -Value $Source
}

funcs.ps1:

Param(
    [parameter(Position=0)]$FunctionName,
    [parameter(Position=1,ValueFromRemainingArguments= $true)]$FunctionArgs
)
. $pwsh\internal\subfuncs.ps1
if($MyInvocation.CommandOrigin -eq "Runspace"){Write-Warning 'Cannot be run interactively';return}
&$FunctionName @FunctionArgs

就是这样!

您不能直接在终端中调用。Start-WindowsTerminalInDirectory