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

zengzsys  于 8个月前  发布在  Shell
关注(0)|答案(2)|浏览(76)

我花了几个小时的时间试图做一个函数,只有在脚本而不是终端运行时才能运行。
我在C:\Users\Alexander\Documents\PowerShell\Profile.ps1中有一个Profile.ps1,它在每个终端示例上运行。类似于Linux .bashrc文件。
在我的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"
}

它不工作。因为当我调用MyPrivateFunction时,它返回为Internal,因为它被MyPrivateFunction函数调用。
因此,即使您直接在终端中输入MyPrivateFunction,它仍然会被视为internal并仍然打印"Hello"
我只想让它按剧本运行。
有点像Python:python if __name__ == __main__
我也试过使用.psm1模块,但它仍然会打印Hello
我试过使用.psm1 module来导入函数,但它仍然会打印Hello,因为我猜它在同一个范围内。
我唯一的解决方案是在每个函数上编写if ($MyInvocation.CommandOrigin -eq "Runspace"),但我认为这不是一个可行的选择,因为有很多代码重复。
一定有比这更好的东西。
我也认为这个问题是独特的,以前没有人问过。因为我已经搜索并尝试了使用PowerShell modules的答案,但它并没有以我想要的方式运行。
我希望它只允许在脚本中运行MyPrivateFunction,而不是通过powershell终端。
它在那里,由于使用点源的funcs.ps1文件。
一种可能的方法是运行一个python脚本并在其中执行所有操作,但这是另一个过程。

z4bn682m

z4bn682m1#

如果你不介意失去制表符补全(这应该没关系,因为你不应该交互地运行函数),一个可能的解决方案是有一个脚本,调用你的函数脚本,执行所需的函数,但只有当它是通过脚本运行。
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
}

然后在你的脚本中只写Call-Function myprivatefunction,或者如果太长的话,把函数名减少到cf或者别的什么,它就是cf myprivatefunction

pbossiut

pbossiut2#

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

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

相关问题