Timetombs

泛义的工具是文明的基础,而确指的工具却是愚人的器物

66h / 116a
,更新于 2024-04-06T22:06:23Z+08:00 by   35f4f88

[PowerShell] Script

版权声明 - CC BY-NC-SA 4.0

1 Script File List

ps1文件列表
#####################################################
# current user powershell profile entry script file.
#####################################################

# params
Param(
    [switch]$Init = $False,
    [string]$GitUserName = 'lnh',
    [string]$GitUserEmail = 'lnhdyx@outlook.com'
)

@(
    '/function.ps1',
    '/log.ps1',
    '/convert.ps1',
    '/env.ps1',
    '/file.ps1',
    '/git.ps1',
    '/vscode.ps1',
    '/gui.ps1',
    '/hosts.ps1',
    '/profile.ps1',
    '/prompt.ps1',
    '/sln.ps1',
    '/ui.ps1',
    '/vm.ps1',
    '/http.ps1',
    '/yaml.ps1',
    '/ip.ps1',
    '/k8s.ps1',
    '/docker.ps1',
    '/hugo.ps1',
    '/java.ps1',
    '/wlan.ps1',
    '/directory.ps1',
    '/idea.ps1',
    '/auto-complete.ps1',
    '/alias.ps1'
) | Foreach-Object { . "$PSScriptRoot$_" }

if ($Init) {

    Profile-AddScriptFile -ProfilePath $PROFILE -ScriptFilePath $PSCOMMANDPATH

    Git-SetGlobalAlias

    Git-SetGlobalConfig

    Git-SetGlobalUser -UserName $GitUserName -UserEmail $GitUserEmail

    Git-GetConfig

    # Update-Help
}

Git-ImportPoshGit

# Kubernetes-ImportPSKubectlCompletion
# UI-SetDisplayOptions

Log-NameValue -Name 'Get-ExecutionPolicy' -Value $(Get-ExecutionPolicy)
################################
# powershell alias functions
################################


Set-Alias -Name d -Value Directory-To
Set-Alias -Name dq -Value Directory-Search-Path-List-From-Quick-Access
Set-Alias -Name dql -Value Directory-List-Quick-Access
Set-Alias -Name c -Value VsCode-Open
Set-Alias -Name i -Value Idea-Open

Set-Alias -Name dr -Value Docker-Run
Set-Alias -Name dre -Value Docker-Run-entrypoint
Set-Alias -Name drs -Value Docker-Run-entrypoint-sh
Set-Alias -Name drb -Value Docker-Run-entrypoint-bash
Set-Alias -Name dc -Value docker-compose
Set-Alias -Name dm -Value docker-machine
Set-Alias -Name k -Value kubectl
Set-Alias -Name mk -Value minikube

Set-Alias -Name e -Value Gui-OpenExplorer

Set-Alias -Name g -Value git

Set-Alias -Name gti -Value git

Set-Alias -Name hs -Value http-server

Set-Alias -Name hus -Value hugo-server

Set-Alias -Name env -Value Env-GetAllVariable

Set-Alias -Name path -Value Env-GetPathVariavle

Set-Alias -Name yj -Value Yaml-ToJson

Set-Alias -Name jy -Value Yaml-FromJson

Set-Alias -Name grep -Value Select-String

Set-Alias -Name k8sgtp -Value Kubernetes-GetTerminatedPod

Set-Alias -Name ja -Value Java-Arthas
# https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/register-argumentcompleter?view=powershell-7.1

Register-ArgumentCompleter -CommandName Directory-To -ParameterName Path -ScriptBlock $__QUICK_ACCESS_DIRECTORY_SCRIPT_BLOCK
Register-ArgumentCompleter -CommandName VsCode-Open -ParameterName Path -ScriptBlock $__QUICK_ACCESS_DIRECTORY_SCRIPT_BLOCK
Register-ArgumentCompleter -CommandName Idea-Open -ParameterName Path -ScriptBlock $__QUICK_ACCESS_DIRECTORY_SCRIPT_BLOCK
Register-ArgumentCompleter -CommandName Gui-OpenExplorer -ParameterName Path -ScriptBlock $__QUICK_ACCESS_DIRECTORY_SCRIPT_BLOCK

Register-ArgumentCompleter -Native -CommandName winget -ScriptBlock {
    param($wordToComplete, $commandAst, $cursorPosition)
    [Console]::InputEncoding = [Console]::OutputEncoding = $OutputEncoding = [System.Text.Utf8Encoding]::new()
    $Local:word = $wordToComplete.Replace('"', '""')
    $Local:ast = $commandAst.ToString().Replace('"', '""')
    winget complete --word="$Local:word" --commandline "$Local:ast" --position $cursorPosition | ForEach-Object {
        [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
    }
}

Register-ArgumentCompleter -Native -CommandName dotnet -ScriptBlock {
    param($wordToComplete, $commandAst, $cursorPosition)
    dotnet complete --position $cursorPosition $commandAst.ToString() | ForEach-Object {
        [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
    }
}

# https://docs.microsoft.com/en-us/powershell/module/psreadline/get-psreadlinekeyhandler?view=powershell-7.1
# Get-PSReadLineKeyHandler
function Byte-Format(
    [Parameter(ValueFromPipeline = $True)]
    [long]$Length
) {
    if ($Length -lt 1KB) {
        return $Length.ToString("#0B")
    }

    if ($Length -lt 1MB) {
        return "$(($Length / 1KB)|Double-Half)KB"
    }

    if ($Length -lt 1GB) {
        return "$(($Length / 1MB)|Double-Half)MB"
    }

    if ($Length -lt 1TB) {
        return "$(($Length / 1GB)|Double-Half)GB"
    }

    if ($Length -lt 1PB) {
        return "$(($Length / 1TB)|Double-Half)TB"
    }

    return "$(($Length / 1PB)|Double-Half)PB"
}

function Double-Half(
    [Parameter(ValueFromPipeline = $True)]
    [Double]$Value
) {
    if ([System.Math]::Floor($Value).CompareTo($Value) -eq 0) {
        return [System.Math]::Floor($Value)
    }

    return [System.Math]::Round($Value, 1)
}

function Mac-Format(
    [Parameter(ValueFromPipeline = $True)]
    [string]$Mac
) {
    $Address = $Null
    if ([System.Net.NetworkInformation.PhysicalAddress]::TryParse($Mac, [ref] $Address) -eq $False) {
        return $Null
    }

    $Hex = $Address.GetAddressBytes() | ForEach-Object { Byte-To-Hex -InputObject $_ }
    return [System.String]::Join(':', $Hex)
}

function Byte-To-Hex() {
    param (
        [Parameter(ValueFromPipeline = $True)]
        [byte]$InputObject
    )
    return $InputObject.ToString('X2');
}
$__QUICK_ACCESS_DIRECTORY = [System.Collections.Generic.List[PSObject]]::new();

$__QUICK_ACCESS_DIRECTORY_SCRIPT_BLOCK = {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
    Directory-Search-Path-List-From-Quick-Access -Search $wordToComplete | ForEach-Object {
        [System.Management.Automation.CompletionResult]::new($_.FullPath, $_.FullPath, 'ParameterValue', $_.FullPath)
    }
}

function Directory-Exists-And-Is-Directory {
    param (
        [Parameter(Mandatory = $TRUE)]
        [string] $Path = $(throw "Path param is null!")
    )

    if (![System.IO.Directory]::Exists($Path)) {
        throw "path $Path is not exist."
    }

    if ([System.IO.File]::Exists($Path)) {
        throw "path $Path is a file."
    }

    return $TRUE;
}

function script:Directory-Get-Abbr {
    param (
        [Parameter(Mandatory = $TRUE)]
        [string] $Name = $(throw "Name param is null!")
    )
    $Abbr = "";
    $Words = $Name.Split(" _.-".ToCharArray(), [System.StringSplitOptions]::RemoveEmptyEntries);
    $Words | ForEach-Object {
        $Abbr += $_[0];
    }
    return $Abbr;
}

function script:Directory-ConvertToDirObject {
    param ($Raw)
    $FullPath = $Raw.FullName;
    $Name = (Split-Path -Path $FullPath -Leaf);
    $NameAbbr = (Directory-Get-Abbr -Name $Name);

    $Parent = (Split-Path -Path $FullPath -Parent);
    $ParentName = (Split-Path -Path $Parent -Leaf);
    $ParentNameAbbr = (Directory-Get-Abbr -Name $ParentName);
    $Dir = New-Object PSObject -Property @{
        #Raw      = $Raw;
        Abbr     = "$ParentNameAbbr$NameAbbr";
        NameAbbr = $NameAbbr;
        FullPath = $FullPath;
    }
    return $Dir
}

function Directory-Add-To-Quick-Access {
    param (
        [string] $Path
    )

    if (Directory-Exists-And-Is-Directory -Path $Path) {
        Get-ChildItem -Path $Path | ForEach-Object {
            if (Test-Path -Path $_.FullName -PathType Container) {
                $__QUICK_ACCESS_DIRECTORY.Add((Directory-ConvertToDirObject -Raw $_))
            }
        }
    }
}

function Directory-List-Quick-Access {
    $__QUICK_ACCESS_DIRECTORY | Format-Table -AutoSize
}

function Directory-Search-Path-List-From-Quick-Access {
    param (
        [Parameter(Mandatory = $TRUE)]
        [string] $Search = $(throw "Search param is null!")
    )

    $ResultWithScopeIndex = [PSObject[][]]::new(10);
    $__QUICK_ACCESS_DIRECTORY | ForEach-Object {
        $Score = Directory-Search-Score -Dir $_ -Search $Search
        if ($Score -gt -1) {
            $ResultWithScopeIndex[$Score] += $_
        }
    }
    [array]::Reverse($ResultWithScopeIndex);

    $Result = [System.Collections.Generic.List[PSObject]]::new();
    $ResultWithScopeIndex | ForEach-Object {
        if ($_ -ne $NULL) {
            $Result.AddRange($_)
        }
    }

    return $Result;
}

function script:Directory-Search-Score {
    param ($Dir, [string] $Search )
    if ($Dir.FullPath.Contains($Search, [StringComparison]::OrdinalIgnoreCase)) {
        return 9;
    }
    if ($Dir.Abbr.Contains($Search, [StringComparison]::OrdinalIgnoreCase)) {
        return 8;
    }
    if ($Dir.NameAbbr.Contains($Search, [StringComparison]::OrdinalIgnoreCase)) {
        return 7;
    }
    if (Filter-Directory-Item -Dir $Dir -Search $Search) {
        return 1;
    }

    return -1;
}


function script:Filter-Directory-Item {
    param ($Dir, [string] $Search )
    $StartIndex = 0;
    for ($i = 0; $i -lt $Search.Length; $i++) {
        $char = $Search[$i];
        $charIndex = $Dir.FullPath.IndexOf($char, $StartIndex);
        if ($charIndex -eq -1) {
            return $FALSE;
        }
        else {
            $StartIndex = $charIndex;
        }
    }
    return $TRUE;
}

function Directory-To {
    param (
        [Parameter(Mandatory = $TRUE)]
        [string] $Path = $(throw "Path param is null!")
    )
    if (Directory-Exists-And-Is-Directory -Path $Path) {
        Log-Debug "cd $Path".ToLower()
        Set-Location $Path
    }
}

Directory-Add-To-Quick-Access -Path d:/_code/
Directory-Add-To-Quick-Access -Path d:/_github/
Directory-Add-To-Quick-Access -Path d:/
Directory-Add-To-Quick-Access -Path d:/_app/
Directory-Add-To-Quick-Access -Path d:/_cache/
function Docker-Run() {
    Log-Debug "docker run --rm --tty --interactive" $Args
    docker run --rm --tty --interactive $Args
}
function Docker-Run-entrypoint() {
    Log-Debug "docker run --rm --tty --interactive --entrypoint" $Args
    docker run --rm --tty --interactive --entrypoint $Args
}

function Docker-Run-entrypoint-sh() {
    Log-Debug "docker run --rm --tty --interactive --entrypoint sh" $Args
    docker run --rm --tty --interactive --entrypoint sh $Args
}

function Docker-Run-entrypoint-bash() {
    Log-Debug "docker run --rm --tty --interactive --entrypoint bash" $Args
    docker run --rm --tty --interactive --entrypoint bash $Args
}
################################
# powershell env functions
################################

[string]$APP_DIR    = 'd:\_app\';
[string]$CACHE_DIR  = 'd:\_cache\';
[string]$CONFIG_DIR = 'd:\_config\';
[string]$DATA_DIR   = 'd:\_data\';

function script:Env-TrySetVariable (
    [string]$Variable = $(throw "Variable is null!"),
    [string]$Value = $(throw "Value is null!")
) {
    $Target = [System.EnvironmentVariableTarget]::Machine

    # 输出旧值
    [string]$OldValue = [System.Environment]::GetEnvironmentVariable($Variable, $Target);
    Log-Info "[$Target][$Variable] OLD_VALUE : " $OldValue

    if ($OldValue -eq $Value) {
        Log-Warn "[$Target][$Variable] NEW_VALUE : " $Value
        return
    }

    # 设置环境变量
    [System.Environment]::SetEnvironmentVariable($Variable, $Value, $Target)

    # 输出新值
    [string]$NewValue = [System.Environment]::GetEnvironmentVariable($Variable, $Target);
    Log-Debug "[$Target][$Variable] NEW_VALUE : " $NewValue
    Write-Host
}

function script:Env-TryAppendPathVariable (
    [string]$Value = $(throw "Value is null!")
) {
    $Target = [System.EnvironmentVariableTarget]::Machine
    $Variable = 'Path'
    # 获取旧值
    [string]$OldValue = [System.Environment]::GetEnvironmentVariable($Variable, $Target);

    # 检测是否已经存在
    if ($OldValue.Split(';').Contains($Value)) {
        Log-Warn "[$Target][$Variable] EXISTS_VALUE : $Value"
        return
    }

    Log-Debug "[$Target][$Variable] APPEND_VALUE : $Value"

    # 追加新值
    [string]$NewValue = $OldValue;
    if ($OldValue.EndsWith(';')) {
        $NewValue = $OldValue + $Value + ';'
    }
    else {
        $NewValue = $OldValue + ';' + $Value + ';'
    }

    Env-TrySetVariable -Variable $Variable -Value $NewValue
}


function Env-TrySetAll() {
    Get-Command -Name 'Env-Set*EnvironmentVariable' -CommandType Function | ForEach-Object {
        Log-Info "RUN : $($_.Name)"
        Invoke-Expression -Command $_.Name
        Write-Host
        Write-Host
    }
}

function Env-GetAllVariable() {
    Get-ChildItem ENV:
}

function Env-GetPathVariavle() {
    $ENV:PATH.Split(';')
}

# https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
function Env-SetXDGEnvironmentVariable() {
    Env-TrySetVariable -Variable 'XDG_CONFIG_HOME' -Value $CONFIG_DIR
    Env-TrySetVariable -Variable 'XDG_CACHE_HOME' -Value $CACHE_DIR
    Env-TrySetVariable -Variable 'XDG_DATA_HOME' -Value $DATA_DIR
}

# https://github.com/MicrosoftArchive/redis/releases
function Env-SetRedisEnvironmentVariable() {
    $APP_REDIS_DIR = $APP_DIR + '_redis\';

    Env-TryAppendPathVariable -Value $APP_REDIS_DIR
}

# https://www.mongodb.org/dl/win32/x86_64-2008plus-ssl
function Env-SetMongoDBEnvironmentVariable() {
    $APP_MONGO_DIR = $APP_DIR + '_mongo\';

    Env-TryAppendPathVariable -Value $APP_MONGO_DIR
}

# https://www.putty.org/
function Env-SetPuttyEnvironmentVariable() {
    $APP_PUTTY_DIR = $APP_DIR + '_putty\';

    Env-TryAppendPathVariable -Value $APP_PUTTY_DIR
}

# https://github.com/shadowsocks/shadowsocks-windows
# function Env-SetShadowsocksEnvironmentVariable() {
#     $APP_SHADOWSOCKS_DIR = $APP_DIR + '_shadowsocks\';

#     Env-TryAppendPathVariable -Value $APP_SHADOWSOCKS_DIR
# }

# https://adoptopenjdk.net/upstream.html
# https://developers.redhat.com/products/openjdk/download
function Env-SetJavaEnvironmentVariable() {
    $APP_JAVA_DIR = $APP_DIR + '_java\';
    $APP_JAVA_BIN_DIR = $APP_JAVA_DIR + 'bin\';

    Env-TrySetVariable -Variable 'JAVA_TOOL_OPTIONS' -Value '-Dfile.encoding=UTF-8'

    Env-TrySetVariable -Variable 'JAVA_HOME' -Value $APP_JAVA_DIR

    Env-TryAppendPathVariable -Value $APP_JAVA_BIN_DIR
}

# https://golang.org/doc/install
function Env-SetGoEnvironmentVariable() {
    $APP_GO_DIR = $APP_DIR + '_go\';
    $APP_GO_BIN_DIR = $APP_GO_DIR + 'bin\';

    $CACHE_GO_DIR = $CACHE_DIR + '_go\';

    Env-TrySetVariable -Variable 'GOROOT' -Value $APP_GO_DIR
    Env-TrySetVariable -Variable 'GOCACHE' -Value $CACHE_GO_DIR
    Env-TryAppendPathVariable -Value $APP_GO_BIN_DIR
}

# https://rubyinstaller.org/downloads/
function Env-SetRubyEnvironmentVariable() {
    $APP_RUBY_DIR = $APP_DIR + '_ruby\';
    $APP_RUBY_BIN_DIR = $APP_RUBY_DIR + 'bin\';

    Env-TrySetVariable -Variable 'RUBY_HOME' -Value $APP_RUBY_DIR
    Env-TryAppendPathVariable -Value $APP_RUBY_BIN_DIR
}

# https://nodejs.org/en/download/
function Env-SetNodeEnvironmentVariable() {
    $APP_NODE_DIR = $APP_DIR + '_node\';
    $APP_NODE_MODULES_DIR = $APP_NODE_DIR + 'node_modules\';

    $CACHE_NODE_DIR = $CACHE_DIR + '_node\';

    Env-TrySetVariable -Variable 'NODE_PATH' -Value $APP_NODE_MODULES_DIR
    Env-TryAppendPathVariable -Value $APP_NODE_DIR

    npm config set cache $CACHE_NODE_DIR --global
    npm config set registry "https://registry.npm.taobao.org" --global
    npm install -g cnpm --registry=https://registry.npm.taobao.org
}


# https://kotlinlang.org/docs/tutorials/command-line.html
function Env-SetKotlinEnvironmentVariable() {
    $APP_KOTLIN_DIR = $APP_DIR + '_kotlin\'
    $APP_KOTLIN_BIN_DIR = $APP_KOTLIN_DIR + 'bin\'

    Env-TryAppendPathVariable -Value $APP_KOTLIN_BIN_DIR
}


# https://dotnet.github.io/
# https://docs.microsoft.com/en-us/dotnet/core/tools/telemetry
function Env-SetNetEnvironmentVariable() {
    Env-TrySetVariable -Variable 'DOTNET_CLI_TELEMETRY_OPTOUT' -Value "true"
}

# https://www.python.org/downloads/windows/
# Windows x86-64 embeddable zip file
function Env-SetPythonEnvironmentVariable() {
    $APP_PYTHON_DIR = $APP_DIR + '_python\';
    $APP_PYTHON_SCRIPTS_DIR = $APP_PYTHON_DIR + 'scripts\';

    Env-TryAppendPathVariable -Value $APP_PYTHON_DIR
    Env-TryAppendPathVariable -Value $APP_PYTHON_SCRIPTS_DIR
}

# https://github.com/icsharpcode/ILSpy/releases
function Env-SetILSpyEnvironmentVariable() {
    $APP_ILSPY_DIR = $APP_DIR + '_ilspy\';

    Env-TryAppendPathVariable -Value $APP_ILSPY_DIR
}

# https://www.nuget.org/downloads
# https://docs.microsoft.com/en-us/nuget/tools/cli-ref-environment-variables
function Env-SetNugetEnvironmentVariable() {
    $APP_NUGET_DIR = $APP_DIR + '_nuget\';

    $CACHE_NUGET_DIR = $CACHE_DIR + '_nuget\';

    Env-TrySetVariable -Variable 'NUGET_PACKAGES' -Value $CACHE_NUGET_DIR
    Env-TryAppendPathVariable -Value $APP_NUGET_DIR
}

# https://developer.android.com/studio/releases/platform-tools.html
function Env-SetADBEnvironmentVariable() {
    $APP_ADB_DIR = $APP_DIR + '_adb\';

    Env-TryAppendPathVariable -Value $APP_ADB_DIR
}

# https://www.cpuid.com/softwares/cpu-z.html
function Env-SetCPUZEnvironmentVariable() {
    $APP_CPUZ_DIR = $APP_DIR + '_cpu-z\';

    Env-TryAppendPathVariable -Value $APP_CPUZ_DIR
}

# https://www.techpowerup.com/gpuz/
function Env-SetGPUZEnvironmentVariable() {
    $APP_GPUZ_DIR = $APP_DIR + '_gpu-z\';

    Env-TryAppendPathVariable -Value $APP_GPUZ_DIR
}

# http://www.superpi.net/Download/
function Env-SetPIEnvironmentVariable() {
    $APP_PI_DIR = $APP_DIR + '_pi\';

    Env-TryAppendPathVariable -Value $APP_PI_DIR
}

# https://maven.apache.org/
function Env-SetMavenEnvironmentVariable() {
    $APP_MAVEN_DIR = $APP_DIR + '_maven\'
    $APP_MAVEN_BIN_DIR = $APP_MAVEN_DIR + 'bin\'
    $CACHE_MAVEN_DIR = $CACHE_DIR + '_maven\'

    # for maven 1
    Env-TrySetVariable -Variable 'MAVEN_HOME' -Value $APP_MAVEN_DIR

    # for maven 2 or 3
    Env-TrySetVariable -Variable 'M2_HOME' -Value $APP_MAVEN_DIR

    # for maven-wrapper https://github.com/takari/maven-wrapper
    Env-TrySetVariable -Variable 'MAVEN_USER_HOME' -Value $APP_MAVEN_DIR

    # http://maven.apache.org/configure.html
    Env-TrySetVariable -Variable 'MAVEN_OPTS' -Value '-Xms256m -Xmx1024m'

    Env-TryAppendPathVariable -Value $APP_MAVEN_BIN_DIR
}

# https://gradle.org/releases/
# https://docs.gradle.org/current/userguide/installation.html
# https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_environment_variables
function Env-SetGradleEnvironmentVariable() {
    $APP_GRADLE_DIR = $APP_DIR + '_gradle\';
    $APP_GRADLE_BIN_DIR = $APP_GRADLE_DIR + 'bin\';

    $CACHE_GRADLE_DIR = $CACHE_DIR + '_gradle\';

    Env-TrySetVariable -Variable 'GRADLE_HOME' -Value $APP_GRADLE_DIR
    Env-TrySetVariable -Variable 'GRADLE_USER_HOME' -Value $CACHE_GRADLE_DIR
    Env-TryAppendPathVariable -Value $APP_GRADLE_BIN_DIR
}

# https://projects.spring.io/spring-boot/
function Env-SetSpringBootCliEnvironmentVariable() {
    $APP_SPRING_BOOT_CLI_DIR = $APP_DIR + '_spring-boot-cli\';
    $APP_SPRING_BOOT_CLI_BIN_DIR = $APP_SPRING_BOOT_CLI_DIR + 'bin\';

    Env-TryAppendPathVariable -Value $APP_SPRING_BOOT_CLI_BIN_DIR
}

# http://httpd.apache.org/download.cgi
function Env-SetHttpdEnvironmentVariable() {
    $APP_HTTPD_DIR = $APP_DIR + '_httpd\';
    $APP_HTTPD_BIN_DIR = $APP_HTTPD_DIR + 'bin\';

    Env-TryAppendPathVariable -Value $APP_HTTPD_BIN_DIR
}

# https://jmeter.apache.org/download_jmeter.cgi
function Env-SetJmeterEnvironmentVariable() {
    $APP_JMETER_DIR = $APP_DIR + '_jmeter\';
    $APP_JMETER_BIN_DIR = $APP_JMETER_DIR + 'bin\';

    Env-TryAppendPathVariable -Value $APP_JMETER_BIN_DIR
}

# http://nginx.org/en/download.html
function Env-SetNginxEnvironmentVariable() {
    $APP_NGINX_DIR = $APP_DIR + '_nginx\';

    Env-TryAppendPathVariable -Value $APP_NGINX_DIR
}

# https://kubernetes.io/docs/tasks/tools/install-kubectl
function Env-SetKubectlEnvironmentVariable() {
    $APP_KUBECTL_DIR = $APP_DIR + '_kubectl\';

    $CONFIG_KUBECTL_DIR = $CONFIG_DIR + '_kubectl\';
    $CONFIG_KUBECTL_CONFIG_FILE = $CONFIG_KUBECTL_DIR + 'config.yml';

    Env-TrySetVariable -Variable 'KUBECONFIG' -Value $CONFIG_KUBECTL_CONFIG_FILE
    Env-TryAppendPathVariable -Value $APP_KUBECTL_DIR
}

# https://github.com/kubernetes/minikube/releases
# function Env-SetMinikubeEnvironmentVariable() {
#     $APP_MINIKUBE_DIR = $APP_DIR + '_minikube\';
#     $DATA_MINIKUBE_DIR = 'e:\_minikube\';

#     Env-TrySetVariable -Variable 'MINIKUBE_HOME' -Value $DATA_MINIKUBE_DIR
#     Env-TrySetVariable -Variable 'MINIKUBE_WANTUPDATENOTIFICATION' -Value 'false'
#     Env-TrySetVariable -Variable 'MINIKUBE_WANTREPORTERRORPROMPT' -Value 'false'
#     Env-TrySetVariable -Variable 'CHANGE_MINIKUBE_NONE_USER' -Value 'true'
#     Env-TryAppendPathVariable -Value $APP_MINIKUBE_DIR
# }

# https://docs.docker.com/engine/reference/commandline/cli/#environment-variables
# https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-socket-option
function Env-SetDockerEnvironmentVariable() {
    $APP_DOCKER_DIR = $APP_DIR + '_docker\';
    $CONFIG_DOCKER_DIR = $CONFIG_DIR + '_docker\';

    Env-TrySetVariable -Variable 'DOCKER_CONFIG' -Value $CONFIG_DOCKER_DIR
    Env-TrySetVariable -Variable 'DOCKER_HOST' -Value 'tcp://127.0.0.1:2375'
    Env-TryAppendPathVariable -Value $APP_DOCKER_DIR
}

# https://docs.docker.com/machine
# https://docs.docker.com/machine/drivers/hyper-v/
# function Env-SetDockerMachineEnvironmentVariable() {
#     $APP_DOCKER_DIR = $APP_DIR + '_docker\';
#     $BOOT2DOCKER_ISO_DIR = 'file://' + $APP_DOCKER_DIR + 'boot2docker.iso';

#     $DATA_DOCKER_DIR = 'e:\_docker\';

#     Env-TrySetVariable -Variable 'MACHINE_STORAGE_PATH' -Value $DATA_DOCKER_DIR
#     Env-TrySetVariable -Variable 'MACHINE_NATIVE_SSH' -Value 1
#     Env-TrySetVariable -Variable 'HYPERV_BOOT2DOCKER_URL' -Value $BOOT2DOCKER_ISO_DIR
#     Env-TrySetVariable -Variable 'HYPERV_VIRTUAL_SWITCH' -Value 'HVS'
#     Env-TrySetVariable -Variable 'HYPERV_CPU_COUNT' -Value 1
#     Env-TrySetVariable -Variable 'HYPERV_MEMORY' -Value 1024
#     Env-TrySetVariable -Variable 'HYPERV_DISK_SIZE' -Value 10240

#     Env-TryAppendPathVariable -Value $APP_DOCKER_DIR
# }

# https://helm.sh/docs
# https://github.com/helm/helm-www
# https://github.com/helm/helm/releases
function Env-SetHelmEnvironmentVariable() {
    $APP_HLEM_DIR = $APP_DIR + '_helm\';

    Env-TryAppendPathVariable -Value $APP_HLEM_DIR
}

# https://github.com/mholt/caddy
# https://caddyserver.com/docs/cli
# function Env-SetCaddyEnvironmentVariable() {
#     $APP_CADDY_DIR = $APP_DIR + '_caddy\';

#     Env-TryAppendPathVariable -Value $APP_CADDY_DIR
# }

# https://coreos.com/os/docs/1911.5.0/overview-of-ct.html
# https://github.com/coreos/container-linux-config-transpiler
# function Env-SetCoreOSEnvironmentVariable() {
#     $APP_COREOS_DIR = $APP_DIR + '_coreos\';

#     Env-TryAppendPathVariable -Value $APP_COREOS_DIR
# }

# https://docs.microsoft.com/en-us/powershell/scripting/overview?view=powershell-6
function Env-SetPowerShellEnvironmentVariable() {
    Env-TrySetVariable -Variable 'POWERSHELL_TELEMETRY_OPTOUT' -Value 'true'
}

# https://github.com/v2ray/v2ray-core
function Env-SetV2RayEnvironmentVariable() {
    $APP_V2RAY_DIR = $APP_DIR + '_v2ray\';

    Env-TryAppendPathVariable -Value $APP_V2RAY_DIR
}

function Env-SetLocaleEnvironmentVariable() {
    Env-TrySetVariable -Variable 'LC_ALL' -Value 'zh_CN.UTF-8'
    Env-TrySetVariable -Variable 'LANG' -Value 'C.UTF-8'
}

# https://www.alex-is.de/PHP/fusion/downloads.php?cat_id=4&download_id=9
function Env-SetASSSDBenchmarkEnvironmentVariable() {
    $APP_AS_SSD_BENCHMARK_DIR = $APP_DIR + '_as-ssd-benchmark\';

    Env-TryAppendPathVariable -Value $APP_AS_SSD_BENCHMARK_DIR
}

# https://crystalmark.info/en/download/
function Env-SetDiskInfoEnvironmentVariable() {
    $APP_DISK_INFO_DIR = $APP_DIR + '_disk-info\';

    Env-TryAppendPathVariable -Value $APP_DISK_INFO_DIR
}

# https://github.com/pbatard/rufus
function Env-SetRufusEnvironmentVariable() {
    $APP_RUFUS_DIR = $APP_DIR + '_rufus\';

    Env-TryAppendPathVariable -Value $APP_RUFUS_DIR
}

# https://github.com/FFmpeg/FFmpeg
function Env-SetFFmpegEnvironmentVariable() {
    $APP_FFMPEG_DIR = $APP_DIR + '_ffmpeg\bin';

    Env-TryAppendPathVariable -Value $APP_FFMPEG_DIR
}

# https://www.rust-lang.org/
function Env-SetRustEnvironmentVariable() {
    $APP_RUSTUP_DIR = $APP_DIR + '_rustup\';
    $APP_CARGO_DIR = $APP_DIR + '_cargo\';
    $APP_CARGO_BIN_DIR = $APP_CARGO_DIR + 'bin\';

    # https://github.com/rust-lang/rustup.rs#environment-variables
    Env-TrySetVariable -Variable 'RUSTUP_HOME' -Value $APP_RUSTUP_DIR
    Env-TrySetVariable -Variable 'RUSTUP_DIST_SERVER' -Value 'http://mirrors.ustc.edu.cn/rust-static'
    Env-TrySetVariable -Variable 'RUSTUP_UPDATE_ROOT' -Value 'http://mirrors.ustc.edu.cn/rust-static/rustup'

    # https://github.com/rust-lang/cargo/blob/master/src/doc/src/reference/environment-variables.md
    Env-TrySetVariable -Variable 'CARGO_HOME' -Value $APP_CARGO_DIR

    Env-TrySetVariable -Variable 'RUST_BACKTRACE' -Value 'full'
    Env-TrySetVariable -Variable 'RUST_TEST_NOCAPTURE' -Value '0'

    Env-TryAppendPathVariable -Value $APP_CARGO_BIN_DIR
}

# https://github.com/gohugoio/hugo
function Env-SetHugoEnvironmentVariable() {
    $APP_HUGO_DIR = $APP_DIR + '_hugo\';
    $CACHE_HUGO_DIR = $CACHE_DIR + '_hugo\';

    Env-TryAppendPathVariable -Value $APP_HUGO_DIR
    Env-TrySetVariable -Variable 'HUGO_CACHEDIR' -Value $CACHE_HUGO_DIR
}

# https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format
# https://wiki.wireshark.org/TLS
function Env-SetSslKeyLogFileEnvironmentVariable() {
    $CACHE_SSL_DIR = $CACHE_DIR + '_ssl\';

    $SSLKEYLOGFILE = $CACHE_SSL_DIR + 'ssl.log';

    Env-TrySetVariable -Variable 'SSLKEYLOGFILE' -Value $SSLKEYLOGFILE
}

# https://dev.mysql.com/downloads/mysql/
# https://dev.mysql.com/doc/refman/8.0/en/windows-install-archive.html
# https://dev.mysql.com/doc/refman/8.0/en/environment-variables.html
function Env-SetMySqlEnvironmentVariable() {
    $APP_MYSQL_DIR = $APP_DIR + '_mysql\';
    $CACHE_MYSQL_DIR = $CACHE_DIR + '_mysql\';
    $DATA_MYSQL_DIR = $DATA_DIR + '_mysql\';
    $APP_MYSQL_BIN_DIR = $APP_MYSQL_DIR + 'bin\';
    $MYSQL_HISTFILE = $CACHE_MYSQL_DIR + '.history';

    Env-TrySetVariable -Variable 'MYSQL_HOME' -Value $APP_MYSQL_DIR
    Env-TrySetVariable -Variable 'MYSQL_DATA' -Value $DATA_MYSQL_DIR
    Env-TrySetVariable -Variable 'MYSQL_HISTFILE' -Value $MYSQL_HISTFILE
    Env-TryAppendPathVariable -Value $APP_MYSQL_BIN_DIR
}

# https://github.com/svenstaro/miniserve
function Env-SetMiniServeEnvironmentVariable() {
    $APP_MINISERVE_DIR = $APP_DIR + '_miniserve\';

    Env-TryAppendPathVariable -Value $APP_MINISERVE_DIR
}

# https://github.com/wagoodman/dive
function Env-SetDiveEnvironmentVariable() {
    $APP_DIVE_DIR = $APP_DIR + '_dive\';

    Env-TryAppendPathVariable -Value $APP_DIVE_DIR
}

# https://www.voidtools.com/zh-cn/
function Env-SetEverythingEnvironmentVariable() {
    $APP_EVERYTHING_DIR = $APP_DIR + '_everything\';

    Env-TryAppendPathVariable -Value $APP_EVERYTHING_DIR
}

# iperf2 https://sourceforge.net/projects/iperf2/
# iperf3 https://iperf.fr/
function Env-SetIperfEnvironmentVariable() {
    $APP_IPERF_DIR = $APP_DIR + '_iperf\';

    Env-TryAppendPathVariable -Value $APP_IPERF_DIR
}

# 杂项工具
function Env-SetOtherEnvironmentVariable() {
    $APP_OTHER_DIR = $APP_DIR + '_other\';

    Env-TryAppendPathVariable -Value $APP_OTHER_DIR
}
################################
# powershell file functions
################################

function File-GetBigFiles ([int]$top = 20) {
    $begin = Get-Date
    Log-Debug "begin..." $begin

    Get-ChildItem -Path $(Get-Location) -File -Recurse |
    Sort-Object Length -Descending |
    Select-Object -First $top |
    Format-Table -Property @{Label = "Size"; Expression = { ($_.Length / 1MB).ToString(('0.000')) + 'MB' } }, FullName -Wrap

    $end = Get-Date
    Log-Debug "end..." $end
    Log-Debug "elapsed times" ($end - $begin)
}


function File-GetAll {
    param (
        [string] $Path = $(Get-Location)
    )

    Get-ChildItem -Path $Path -Directory | ForEach-Object {
        File-GetAll -Path $_
    }

    Get-ChildItem -Path $Path -File | ForEach-Object {
        $_.FullName
    }
}

function File-Diff {
    param (
        [string] $PartFile,
        [string] $FullFile
    )

    $PartContent = $(Get-Content $PartFile)
    Get-Content -Path $FullFile | ForEach-Object {
        if ($PartContent.Contains($_) -eq $FALSE) {
            $_
        }
    }
}

function Read-Host-With-Default {
    param (
        [String]$Prompt,
        [String]$DefaultValue
    )
    $Input = Read-Host -Prompt "$Prompt,default $DefaultValue"
    $Input = (-not($input))?"$DefaultValue":"$Input"
    Write-host "$Prompt $Input" -ForegroundColor Green
    return $Input
}
################################
# git functions
################################

# import posh-git module
function Git-ImportPoshGit () {
    Import-Module posh-git
}

# install posh-git module
function Git-InstallPoshGit () {
    Install-Module posh-git
}

# recurse git pull rebase
function Git-Pull-Rebase-Recurse () {
    Get-ChildItem -Attributes Directory -Path (Get-Location) | ForEach-Object {
        $Path = $_.FullName.ToLower()
        Log-Debug "`ncd $Path"
        Set-Location $Path

        Log-Debug 'git remote -v'
        git remote -v

        Log-Debug 'git symbolic-ref HEAD'
        git symbolic-ref HEAD

        Log-Debug "git pull --rebase"
        git pull --rebase

        Set-Location -Path ..
    }
}


function Git-Warn-GC () {
    Log-Debug "git reflog expire --expire=now --all"
    git warn-expire-reflog
    Log-Debug "git gc --prune=now --aggressive"
    git warn-gc-now
    Log-Debug "git count-objects -v -H"
    git size
}

function Git-Warn-GC-Recurse () {
    Get-ChildItem -Attributes Directory -Path (Get-Location) | ForEach-Object {
        $Path = $_.FullName.ToLower()
        Log-Debug "`ncd $Path"
        Set-Location $Path
        Git-Warn-GC
        Set-Location -Path ..
    }
}

function Git-Size-Recurse () {
    Get-ChildItem -Attributes Directory -Path (Get-Location) | ForEach-Object {
        $Path = $_.FullName.ToLower()
        Log-Debug "`ngit -C '$Path' count-objects -v -H"
        git -C "$Path" size
    }
}

function script:Git-GetAllObjects () {
    $gitObjects = git rev-list --objects --all | git cat-file --batch-check='%(objecttype)|%(objectname)|%(objectsize)|%(rest)'
    return $gitObjects
}

function script:Git-ConvertToPSObject ($object) {
    $row = $object.Split('|')

    $gitObject = New-Object PSObject -Property @{
        type = $row[0];
        sha  = $row[1];
        size = [int]($row[2]);
        path = $row[3];
    }

    return $gitObject
}

function script:Git-GetAllBlobObjects () {
    $gitBlobObjects = @()
    Git-GetAllObjects | Foreach-Object {
        if ($_.StartsWith('blob')) {
            $gitBlobObjects += (Git-ConvertToPSObject $_)
        }
    }
    return $gitBlobObjects
}


function Git-GetBigFiles([int]$top = 20) {
    $begin = Get-Date
    Log-Debug "begin..." $begin

    Git-GetAllBlobObjects |
    Sort-Object size -Descending |
    Select-Object -First $top |
    Format-Table -Property sha, @{Label = "size"; Expression = { ($_.size / 1MB).ToString(('0.000')) + 'MB' } }, path -Wrap

    $end = Get-Date
    Log-Debug "end..." $end
    Log-Debug "elapsed times" ($end - $begin)
}

function Git-SetGlobalAlias () {

    # checkout
    git config --global alias.co checkout

    # commit
    git config --global alias.ci commit
    git config --global alias.alc 'commit --amend --no-edit'

    # status
    git config --global alias.st 'status --short --branch'

    # branch
    git config --global alias.br branch

    # pull
    git config --global alias.pr 'pull --rebase'

    # merge
    git config --global alias.mnf 'merge --no-ff'

    # diff
    git config --global alias.d diff
    git config --global alias.dt difftool

    # cherry-pick
    git config --global alias.cp cherry-pick

    # log
    git config --global alias.last 'log -1'
    git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

    # count-objects
    git config --global alias.size 'count-objects -v -H'

    # reflog
    git config --global alias.rl "reflog --format='%cd %h %gs' --date=format:'%Y-%m-%d %H:%M:%S'"

    # gc
    git config --global alias.warn-expire-reflog "reflog expire --expire=now --all"
    git config --global alias.warn-gc-now "gc --prune=now --aggressive"

    # chmod +/- x
    git config --global alias.chmod644 "update-index --chmod=-x"
    git config --global alias.chmod755 "update-index --chmod=+x"

    # head
    git config --global alias.head 'symbolic-ref HEAD'
}

# set global config
function Git-SetGlobalConfig () {

    git config --global init.defaultBranch main

    # gui
    git config --global gui.encoding 'utf-8'

    # i18n
    git config --global i18n.commitencoding 'utf-8'
    git config --global core.quotepath false

    # editor
    git config --global core.editor "code -w"
    git config --global core.autocrlf false
    git config --global core.safecrlf true
    git config --global core.filemode false

    # color
    git config --global color.ui true

    # branch pager
    git config --global pager.branch false
}

# set git global user
function Git-SetGlobalUser (
    [string] $UserName = $(throw "UserName is null!"),
    [string] $UserEmail = $(throw "UserEmail is null!")
) {

    git config --global user.name $UserName
    git config --global user.email $UserEmail
}

# get git user
function Git-GetCurrentUser () {

    $UserName = git config user.name
    $UserEmail = git config user.email
    return "$UserName@<$UserEmail>"
}

# git get config
function Git-GetConfig ([string]$Name) {
    if ($Name) {
        $Values = git config --get-all $Name
        $LocalValues = git config --get-all --local $Name
        $GlobalValues = git config --get-all --global $Name
        $SystemValues = git config --get-all --system $Name

        Write-Host "name   : $Name" -ForegroundColor Green
        Write-Host "value  : $Values" -ForegroundColor Green
        Write-Host "local  : $LocalValues" -ForegroundColor Green
        Write-Host "global : $GlobalValues" -ForegroundColor Green
        Write-Host "system : $SystemValues" -ForegroundColor Green
    }
    else {
        git config --list | Sort-Object
    }
}

function Git-Proxy(
    [switch]$set = $False,
    [switch]$get = $True,
    [switch]$unset = $False
) {
    if ($set) {
        git config --global http.proxy 'socks5://192.168.2.123:1080'
    }

    if ($unset) {
        git config --global --unset http.proxy
        git config --global --unset https.proxy
    }

    git config --global --get http.proxy
    git config --global --get https.proxy
}
git clone https://github.com/linianhui/benchmark-http.git
git clone https://github.com/linianhui/benchmark-nginx.git
git clone https://github.com/linianhui/blog.git
git clone https://github.com/linianhui/channel9-downloader.git
git clone https://github.com/linianhui/chrome-extensions.git
git clone https://github.com/linianhui/cnblogs-theme.git
git clone https://github.com/linianhui/code.git
git clone https://github.com/linianhui/code-guide.git
git clone https://github.com/linianhui/div.git
git clone https://github.com/linianhui/docker.git
git clone https://github.com/linianhui/example-aspnetcore.git
git clone https://github.com/linianhui/example-cake.git
git clone https://github.com/linianhui/example-java.git
git clone https://github.com/linianhui/example-mongodb.git
git clone https://github.com/linianhui/example-oidc.git
git clone https://github.com/linianhui/example-rabbitmq.git
git clone https://github.com/linianhui/example-spring.git
git clone https://github.com/linianhui/git-web.git
git clone https://github.com/linianhui/I-love-mommy.git
git clone https://github.com/linianhui/jvm.git
git clone https://github.com/linianhui/linianhui.github.io.git
git clone https://github.com/linianhui/networking.git
git clone https://github.com/linianhui/networking-programming.git
git clone https://github.com/linianhui/nuget-server.git

function Gui-OpenExplorer () {
    param (
        [Parameter(Mandatory = $TRUE)]
        [string] $Path = $(throw "Path param is null!")
    )
    if (Directory-Exists-And-Is-Directory -Path $Path) {
        Log-Debug "explorer $Path".ToLower()
        explorer $Path
    }
}

function Hosts-Edit () {
  code "$ENV:SYSTEMROOT\system32\drivers\etc\hosts"
}

# https://github.com/svenstaro/miniserve
function Http-Server() {
    Log-Debug "miniserve --color-scheme squirrel --qrcode --upload-files[-u]" $Args
    miniserve --color-scheme squirrel --qrcode $Args
}
function Hugo-Server() {
    Log-Debug " hugo server --config hugo.yml --watch --buildDrafts --forceSyncStatic --panicOnWarning --port 13131"
    hugo server --config hugo.yml --watch --buildDrafts --forceSyncStatic --panicOnWarning --port 13131
}
function Idea-Open {
    param (
        [Parameter(Mandatory = $TRUE)]
        [string] $Path = $(throw "Path param is null!")
    )
    if (Directory-Exists-And-Is-Directory -Path $Path) {
        Log-Debug "idea64 $Path".ToLower()
        idea64 $Path
    }
}
################################
# powershell ip functions
################################

function set-ip() {
    # show all ethernet interfaces
    netsh interface ipv4 show interfaces

    $defaultIdx=1
    $idx = Read-Host-With-Default -Prompt "select interface idx" -DefaultValue $defaultIdx

    # show selected ethernet interface address
    netsh interface ipv4 show address name=$idx

    # set dhcp
    $dhcp = Read-Host-With-Default -Prompt "set source=[dhcp|static]" -DefaultValue 'static'

    if ('dhcp' -ieq $dhcp) {
        netsh interface ipv4 set address name=$idx source=dhcp

        Write-host "show interface $idx current address" -ForegroundColor Green
        netsh interface ipv4 show address name=$idx
        return
    }

    $defaultIP = '192.168.100.2'
    $ip = Read-Host-With-Default -Prompt 'set ip' -DefaultValue $defaultIP

    $defaultMask = '255.255.255.0'
    $mask = Read-Host-With-Default -Prompt 'set mask' -DefaultValue $defaultMask

    $defaultGateway = $defaultIP.Substring(0, $defaultIP.LastIndexOf('.')) + '.1'
    $gateway = Read-Host-With-Default -Prompt 'set gateway' -DefaultValue $defaultGateway

    netsh interface ipv4 set address name=$idx source=static address=$ip mask=$mask gateway=$gateway
    Write-host "netsh interface ipv4 show address name=$idx" -ForegroundColor Green
    netsh interface ipv4 show address name=$idx
}

function IP-Port-Forward-Add (
    [int] $port,
    [string] $ip
) {
    Log-Debug "netsh interface portproxy add v4tov4 listenport=$port connectaddress=$ip connectport=$port"
    netsh interface portproxy add v4tov4 listenport=$port connectaddress=$ip connectport=$port
}

function IP-Port-Forward-Delete (
    [int] $port
) {
    Log-Debug "netsh interface portproxy delete v4tov4 listenport=$port"
    netsh interface portproxy delete v4tov4 listenport=$port
}


function IP-Port-Forward-Show (
) {
    Log-Debug "netsh interface portproxy show all"
    netsh interface portproxy show all
}
function Java-Arthas() {
    # https://arthas.gitee.io/install-detail.html
    Log-Debug "java -jar $ENV:JAVA_HOME\arthas-boot.jar --repo-mirror aliyun --use-http $ARGS"
    java -jar $ENV:JAVA_HOME\arthas-boot.jar --repo-mirror aliyun --use-http $ARGS
}

function Java-Set-Jdk {
    param (
        [ValidateSet('8', '11', '17', '19')]
        [string] $Version
    )
    $BasePath = 'd:\_app\_java'
    $JdkPath = $BasePath + $Version

    $CurrentJdkPath = (Get-Item -Path $BasePath).Target
    Log-Info "current jdk path : $CurrentJdkPath"

    if ($JdkPath.Equals($CurrentJdkPath)) {
        Log-Warn "not need change"
    }
    else {
        Log-Warn "Remove-Item $BasePath -Force -Confirm:$False"
        Remove-Item $BasePath -Force -Confirm:$False

        Log-Info "New-Item -ItemType Junction -Path $BasePath -Target $JdkPath | Out-Null"
        New-Item -ItemType Junction -Path $BasePath -Target $JdkPath | Out-Null
    }

    Log-Debug "now jdk path : $((Get-Item -Path $BasePath).Target)"
    java -version
}

# https://github.com/mziyabo/PSKubectlCompletion
function Kubernetes-ImportPSKubectlCompletion () {
    Import-Module -Name PSKubectlCompletion
    Register-KubectlCompletion
}

function Kubernetes-InstallPSKubectlCompletion () {
    Install-Module PSKubectlCompletion
}

function Kubernetes-GetTerminatedPod() {
    kubectl get pods -o custom-columns-file=D:\_code\blog\src\k8s\kubectl\terminated-pod.txt --sort-by='{status.containerStatuses[0].lastState.terminated.finishedAt}' $Args
}
function Log-Warn() {
    Write-Host $Args -ForegroundColor Yellow
}

function Log-Debug() {
    Write-Host $Args -ForegroundColor Green
}

function Log-Info() {
    Write-Host $Args -ForegroundColor Gray
}

function Log-NameValue(
    [string] $Name,
    [int] $NamePadding,
    [string] $Value
) {
    Write-Host -NoNewline $Name.PadRight($NamePadding)" : "
    Write-Host $Value -ForegroundColor Green
}
################################
# powershell profile functions
################################

function script:Profile-New(
    [string] $ProfilePath = $(throw "ProfilePath is null!")
) {
    if (Test-Path $ProfilePath) {
        Log-Info "# $ProfilePath already existed."
    }
    else {
        New-Item -Path $Profile -ItemType File -Force
        Log-Debug "# Create [$ProfilePath] succeed."
    }
}

function Profile-AddScriptExpression (
    [string] $ProfilePath = $(throw "ProfilePath is null!"),
    [string] $ScriptExpression = $(throw "ScriptExpression is null!")
) {
    Profile-New -ProfilePath $ProfilePath

    $ProfileContent = Get-Content -Path $ProfilePath
    if ($ProfileContent -contains $ScriptExpression) {
        Log-Info "# [$ScriptExpression] already existed in $ProfilePath."
    }
    else {
        Set-Content -Path $ProfilePath -Value "$ProfileContent`r`n$ScriptExpression"
        Log-Debug "# [$ScriptExpression] append to $ProfilePath."
    }
}

function Profile-AddScriptFile (
    [string] $ProfilePath = $(throw "ProfilePath is null!"),
    [string] $ScriptFilePath = $(throw "ScriptFilePath is null!")
) {
    if (!(Test-Path $ScriptFilePath)) {
        throw "$ScriptFilePath not found."
    }

    Profile-AddScriptExpression -ProfilePath $ProfilePath -ScriptExpression ". ""$ScriptFilePath"""
}
################################
# powershell prompt functions
################################

function prompt () {
    # hold last exit code
    $OLD_LASTEXITCODE = $LASTEXITCODE

    $Now = [System.DateTimeOffset]::Now
    $CurrentYearLastDay = New-Object -TypeName System.DateOnly -ArgumentList ($Now.Year, 12, 31)
    $DateTime = $Now.ToString('yy-MM-dd HH:mm:ss K')
    $DayOfWeek = [System.Int32]$Now.DayOfWeek
    $Week = $DayOfWeek.Equals(0)?7:$DayOfWeek
    $DayOfYear = $Now.DayOfYear
    $WeekOfYear = [System.Math]::Round(($DayOfYear + 7) / 7)
    $ResidueWeekOfYear = [System.Math]::Round(($CurrentYearLastDay.DayOfYear - $DayOfYear) / 7)
    $DayOfNewYear = $CurrentYearLastDay.DayOfYear - $DayOfYear
    $UnixTimeMilliseconds = $Now.ToUnixTimeMilliseconds()
    $UserPrompt = UI-GetUserPrompt
    $UserPromptPrefix = $UserPrompt.Prefix
    $UserPromptText = $UserPrompt.Text

    Write-Host -NoNewline "`n$UserPromptText $DateTime $UnixTimeMilliseconds w$Week-$WeekOfYear-$ResidueWeekOfYear d$DayOfYear-$DayOfNewYear" -ForegroundColor Gray
    if ($OLD_LASTEXITCODE -gt 0) {
        Write-Host -NoNewline " $OLD_LASTEXITCODE" -ForegroundColor Red
    }

    # if working directory is git repository
    if (Get-GitStatus) {

        # get git user.name and user.email
        $GitUser = Git-GetCurrentUser

        # show git user.name and user.email
        Write-Host -NoNewline "`n$UserPromptPrefix $GitUser :" -ForegroundColor Gray

        # show git status
        Write-Host -NoNewline (Write-VcsStatus)
    }

    Write-Host

    # show current work directory in window title
    $Host.UI.RawUI.WindowTitle = $UserPromptText

    # reset last exit code
    $LASTEXITCODE = $OLD_LASTEXITCODE

    return "$UserPromptPrefix "
}
########################################
# powershell open visual studio sln file
########################################

function script:Sln-GetFiles() {
    $currentPath = Get-Location
    Log-Debug 'current path : ' $currentPath

    $slnFiles = Get-ChildItem -Path $currentPath -File -Filter *.sln

    return $slnFiles
}

function script:Sln-SelectFile($slnFiles) {
    if ($slnFiles.Count -eq 0) {
        throw 'sln file not found.'
    }

    if ($slnFiles.Count -eq 1) {
        return $slnFiles[0]
    }

    [int]$i = 0
    $slnFiles | ForEach-Object {
        Write-Host $i ': ' $_.Name
        $i++
    }

    [int]$index = Read-Host 'find more sln file, please input index (default 0) :'
    return $slnFiles[$index]
}

function Sln() {
    $slnFiles = Sln-GetFiles
    $slnFile = Sln-SelectFile $slnFiles
    Log-Debug 'opening...   : ' $slnFile
    Invoke-Item $slnFile
}
################################
# powershell ui functions
################################

function Ui-Test-Administrator {
    $CurrentUser = [Security.Principal.WindowsIdentity]::GetCurrent();
    $CurrentPrincipal = New-Object Security.Principal.WindowsPrincipal $CurrentUser;
    return $CurrentPrincipal.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}

function script:UI-GetUserName() {
    $UserName = $ENV:USERNAME.ToLower();
    if($UserName -eq 'administrator'){
        return 'admin';
    }
    return $UserName;
}

function script:UI-GetComputerName() {
    return $ENV:COMPUTERNAME.ToLower();
}

function UI-GetUserPrompt() {
    $Role = '$';
    $UserName = UI-GetUserName
    $ComputerName = UI-GetComputerName
    $CurrentPath = $(Get-Location).ToString().ToLower();
    if (Ui-Test-Administrator) {
        $Role = '#'
    }

    return @{
        Prefix       = $Role;
        UserName     = $UserName;
        ComputerName = $ComputerName;
        Text         = "$Role $UserName@$ComputerName $CurrentPath"
    }
}

function UI-SetDisplayOptions () {
    $Host.UI.RawUI.WindowPosition.X = 0;
    $Host.UI.RawUI.WindowPosition.Y = 0;

    $Host.UI.RawUI.BufferSize.Width = 80;
    $Host.UI.RawUI.BufferSize.Height = 2000;

    $Host.UI.RawUI.WindowSize.Width = 80;
    $Host.UI.RawUI.WindowSize.Height = 40;

    $Host.UI.RawUI.MaxWindowSize.Width = 80;
    $Host.UI.RawUI.MaxWindowSize.Height = 40;

    $Host.UI.RawUI.ForegroundColor = "White";
    $Host.UI.RawUI.BackgroundColor = "Black";
}
################################
# powershell vm(hyper-v) functions
################################

function vm ([string] $name) {
    if ([String]::IsNullOrEmpty($name)) {
        Get-VM
    }
    else {
        Get-VM -Name $name
    }
}

# https://docs.microsoft.com/en-us/powershell/module/hyper-v/new-vhd?view=win10-ps
function vhd-create(
    [string] $Path,
    [uint64] $Size = 128GB
) {
    Log-Debug "New-VHD -Dynamic -Path $Path -SizeBytes $Size"
    New-VHD `
        -Dynamic `
        -Path $Path `
        -SizeBytes $Size
}

# https://www.altaro.com/hyper-v/customize-vm-powershell/
# https://docs.microsoft.com/en-us/powershell/module/hyper-v/new-vm?view=win10-ps
# https://docs.microsoft.com/en-us/powershell/module/hyper-v/set-vm?view=win10-ps
# https://docs.microsoft.com/en-us/powershell/module/hyper-v/set-vmdvddrive?view=win10-ps
# https://learn.microsoft.com/zh-cn/windows-server/virtualization/hyper-v/best-practices-for-running-linux-on-hyper-v
function Vm-From-Json(
    [string] $JsonFilePath
) {
    $NamePadding = 22
    if ((Test-Path -Path $JsonFilePath -PathType Leaf) -eq $False) {
        Log-NameValue -Name 'not_found' -NamePadding $NamePadding -Value "$JsonFilePath"
        Log-NameValue -Name 'help' -NamePadding $NamePadding -Value 'https://linianhui.github.io/powershell/hyper-v/#config'
        return
    }

    if ((Ui-Test-Administrator) -eq $False) {
        Log-NameValue -Name 'no_permission' -NamePadding $NamePadding -Value "need use administrator"
        return
    }

    $Json = Get-Content -Path $JsonFilePath | ConvertFrom-Json

    $VhdPath = ($Json.vhd.path + "\" + $Json.name + ".vhdx")
    if ((Test-Path -Path $VhdPath -PathType Leaf) -eq $False) {
        New-VHD `
            -Dynamic `
            -Path $VhdPath `
            -BlockSizeBytes $Json.vhd.blockSize `
            -SizeBytes $Json.vhd.size | Out-Null
    }

    $VM = Get-VM -Name $Json.name -ErrorAction Ignore
    if ($VM -eq $NULL) {
        New-VM `
            -Name $Json.name `
            -Generation $Json.generation `
            -Path $Json.path `
            -SwitchName $Json.net.switch `
            -VHDPath $VhdPath | Out-Null
    }

    if ($VM.Generation -eq 2) {
        # https://learn.microsoft.com/en-us/powershell/module/hyper-v/set-vmfirmware?view=windowsserver2019-ps
        Set-VMFirmware `
            -VMName $Json.name `
            -EnableSecureBoot $Json.boot.secure
    }

    # https://learn.microsoft.com/en-us/powershell/module/hyper-v/set-vm?view=windowsserver2019-ps
    Set-VM `
        -Name $Json.name `
        -AutomaticStartAction $Json.automatic.start `
        -AutomaticStopAction $Json.automatic.stop `
        -AutomaticCheckpointsEnabled $Json.automatic.checkpoint `
        -CheckpointType $Json.checkpoint.type

    Get-VMIntegrationService -VMName $Json.name | ForEach-Object {
        Enable-VMIntegrationService -VMName $Json.name -Name $_.Name
    }

    # print vm
    $VM = Get-VM -Name $Json.name
    Log-NameValue -Name 'name' -NamePadding $NamePadding -Value $VM.Name
    Log-NameValue -Name 'generation' -NamePadding $NamePadding -Value $VM.Generation
    Log-NameValue -Name 'path' -NamePadding $NamePadding -Value $VM.Path
    Log-NameValue -Name 'state' -NamePadding $NamePadding -Value $VM.State
    if ($VM.Generation -eq 2) {
        $VMFirmware = Get-VMFirmware -VMName $Json.name
        Log-NameValue -Name 'boot.secure' -NamePadding $NamePadding -Value $VMFirmware.SecureBoot.ToString()
    }
    else {
        Log-NameValue -Name 'boot.secure' -NamePadding $NamePadding -Value 'Off'
    }
    Log-NameValue -Name 'automatic.start' -NamePadding $NamePadding -Value $VM.AutomaticStartAction
    Log-NameValue -Name 'automatic.stop' -NamePadding $NamePadding -Value $VM.AutomaticStopAction
    Log-NameValue -Name 'automatic.checkpoint' -NamePadding $NamePadding -Value $VM.AutomaticCheckpointsEnabled
    Log-NameValue -Name 'checkpoint.type' -NamePadding $NamePadding -Value $VM.CheckpointType

    # https://learn.microsoft.com/en-us/powershell/module/hyper-v/set-vmprocessor?view=windowsserver2019-ps
    Set-VMProcessor `
        -VMName $Json.name `
        -Count $Json.cpu.count
    $CPU = Get-VMProcessor -VMName $Json.name
    # print cpu
    Log-NameValue -Name 'cpu.count' -NamePadding $NamePadding -Value $CPU.Count


    # https://learn.microsoft.com/en-us/powershell/module/hyper-v/set-vmmemory?view=windowsserver2019-ps
    Set-VMMemory `
        -VMName $Json.name `
        -DynamicMemoryEnabled $True `
        -StartupBytes $Json.mem.min `
        -MinimumBytes $Json.mem.min `
        -MaximumBytes $Json.mem.max
    $MEM = Get-VMMemory -VMName $Json.name
    # print mem
    Log-NameValue -Name 'mem.dynamic' -NamePadding $NamePadding -Value $MEM.DynamicMemoryEnabled
    Log-NameValue -Name 'mem.startup' -NamePadding $NamePadding -Value ($MEM.Startup | Byte-Format)
    Log-NameValue -Name 'mem.min' -NamePadding $NamePadding -Value ($MEM.Minimum | Byte-Format)
    Log-NameValue -Name 'mem.max' -NamePadding $NamePadding -Value ($MEM.Maximum | Byte-Format)


    if ($Json.net.mac) {
        Set-VMNetworkAdapter `
            -VMName $Json.name `
            -StaticMacAddress $Json.net.mac
    }
    $VM = Get-VM -Name $Json.name
    # print net
    Log-NameValue -Name 'net.switch' -NamePadding $NamePadding -Value $VM.NetworkAdapters[0].SwitchName
    Log-NameValue -Name 'net.connected' -NamePadding $NamePadding -Value $VM.NetworkAdapters[0].Connected
    Log-NameValue -Name 'net.mac' -NamePadding $NamePadding -Value ($VM.NetworkAdapters[0].MacAddress | Mac-Format)


    $VHD = Get-VHD -Path $VhdPath
    $HDD = Get-VMHardDiskDrive -VMName $Json.name
    # print hdd
    Log-NameValue -Name 'vhd.type' -NamePadding $NamePadding -Value $VHD.VhdType
    Log-NameValue -Name 'vhd.path' -NamePadding $NamePadding -Value $VHD.Path
    Log-NameValue -Name 'vhd.format' -NamePadding $NamePadding -Value $VHD.VhdFormat
    Log-NameValue -Name 'vhd.size' -NamePadding $NamePadding -Value ($VHD.Size | Byte-Format)
    Log-NameValue -Name 'vhd.blocksize' -NamePadding $NamePadding -Value ($VHD.BlockSize | Byte-Format)
    Log-NameValue -Name 'vhd.fileSize' -NamePadding $NamePadding -Value ($VHD.FileSize | Byte-Format)
    Log-NameValue -Name 'vhd.controllerType' -NamePadding $NamePadding -Value $HDD.ControllerType
    Log-NameValue -Name 'vhd.controllerNumber' -NamePadding $NamePadding -Value $HDD.ControllerNumber
    Log-NameValue -Name 'vhd.controllerLocation' -NamePadding $NamePadding -Value $HDD.ControllerLocation


    if ($Json.dvd.iso) {
        if (Test-Path -Path $Json.dvd.iso -PathType Leaf) {
            if ((Get-VMDvdDrive -VMName $Json.name) -eq $Null) {
                Add-VMDvdDrive `
                    -VMName $Json.name `
                    -Path $Json.dvd.iso`
                    -ErrorAction Ignore
            }
        }
        $DVD = Get-VMDvdDrive -VMName $Json.name
        if ($DVD.Path) {
            # print dvd
            Log-NameValue -Name 'dvd.type' -NamePadding $NamePadding -Value $DVD.DvdMediaType
            Log-NameValue -Name 'dvd.path' -NamePadding $NamePadding -Value $DVD.Path
            Log-NameValue -Name 'dvd.fileSize' -NamePadding $NamePadding -Value ((Get-Item $DVD.Path).Length | Byte-Format)
            Log-NameValue -Name 'dvd.controllerType' -NamePadding $NamePadding -Value $DVD.ControllerType
            Log-NameValue -Name 'dvd.controllerNumber' -NamePadding $NamePadding -Value $DVD.ControllerNumber
            Log-NameValue -Name 'dvd.controllerLocation' -NamePadding $NamePadding -Value $DVD.ControllerLocation
        }
    }
}


function Vm-To-Json() {
    param (
        [string] $VMName = $(throw "VMName is null!")
    )

    $NamePadding = 22

    if ((Ui-Test-Administrator) -eq $False) {
        Log-NameValue -Name 'no_permission' -NamePadding $NamePadding -Value 'need use administrator'
        return
    }

    $VM = Get-VM -Name $VMName -ErrorAction Ignore
    if ($VM -eq $NULL) {
        Log-NameValue -Name 'not_found' -NamePadding $NamePadding -Value $VMName
        return
    }

    $AutomaticJson = [ordered]@{
        'start'      = $VM.AutomaticStartAction.ToString()
        'stop'       = $VM.AutomaticStopAction.ToString()
        'checkpoint' = $VM.AutomaticCheckpointsEnabled
    }

    $CheckpointJson = [ordered]@{
        'type' = $VM.CheckpointType.ToString()
    }

    $BootJson = [ordered]@{
        'secure' = 'Off'
    }
    if ($VM.Generation -eq 2) {
        $Boot = Get-VMFirmware -VMName $VM.Name
        $BootJson.secure = $Boot.SecureBoot.ToString()
    }

    $Cpu = Get-VMProcessor -VMName $VM.Name
    $CpuJson = [ordered]@{
        'count' = $Cpu.Count
    }

    $Mem = Get-VMMemory -VMName $VM.Name
    $MemJson = [ordered]@{
        'min' = ($Mem.Minimum | Byte-Format)
        'max' = ($Mem.Maximum | Byte-Format)
    }

    $NetJson = [ordered]@{
        'switch' = $VM.NetworkAdapters[0].SwitchName
        'mac'    = ($VM.NetworkAdapters[0].MacAddress | Mac-Format)
    }

    $VhdPath = (Get-VMHardDiskDrive -VMName $VM.Name)[0].Path
    $Vhd = Get-VHD -Path $VhdPath
    $VhdJson = [ordered]@{
        'path'      = (Get-ChildItem -Path $Vhd.Path).DirectoryName.ToLower()
        'size'      = ($Vhd.Size | Byte-Format)
        'blockSize' = ($Vhd.BlockSize | Byte-Format)
    }

    $Dvd = Get-VMDvdDrive -VMName $VM.Name
    $DvdJson = [ordered]@{
        "iso" = $Dvd.Path?.ToLower()
    }

    $Json = [ordered]@{
        'name'       = $VM.Name
        'generation' = $VM.Generation
        'path'       = $VM.Path.ToLower()
        'automatic'  = $AutomaticJson
        'boot'       = $BootJson
        'checkpoint' = $CheckpointJson
        'cpu'        = $CpuJson
        'mem'        = $MemJson
        'net'        = $NetJson
        'vhd'        = $VhdJson
        'dvd'        = $DvdJson
    }

    $Json | ConvertTo-Json
}

function vm-run ([string] $name) {
    if ((Ui-Test-Administrator) -eq $False) {
        Log-NameValue -Name 'no_permission' -NamePadding 20 -Value 'use administrator run vm'
        return
    }
    Get-VM -Name $name | Start-VM
}

function vm-stop ([string] $name) {
    if ((Ui-Test-Administrator) -eq $False) {
        Log-NameValue -Name 'no_permission' -NamePadding 10 -Value 'use administrator stop vm'
        return
    }
    Get-VM -Name $name | Stop-VM
}

function vm-ssh (
    [string]$username,
    [string]$hostname,
    [string]$port = 22) {

    Log-Debug "run [$hostname] hyper-v vm"
    vm-run -name $hostname

    Log-Debug "ssh $username@$hostname -p $port"
    ssh "$username@$hostname" -p $port
}

function ubt1 () {
    vm-ssh -username root -hostname ubt1
}

function ubt2 () {
    vm-ssh -username root -hostname ubt2
}

function ubt3 () {
    vm-ssh -username root -hostname ubt3
}

function ceos () {
    vm-ssh -username root -hostname ceos
}

function deb1 () {
    vm-ssh -username root -hostname deb1
}

function deb2 () {
    vm-ssh -username root -hostname deb2
}

function deb3 () {
    vm-ssh -username root -hostname deb3
}
function VsCode-Open {
    param (
        [Parameter(Mandatory = $TRUE)]
        [string] $Path = $(throw "Path param is null!")
    )
    if (Directory-Exists-And-Is-Directory -Path $Path) {
        Log-Debug "code $Path".ToLower()
        code $Path
    }
}
function WLAN-Export {
    Log-Debug "netsh wlan export profile key=clear"
    netsh wlan export profile key=clear
}
# https://github.com/jeremyfa/yaml.js
# cnpm install -yamljs -g

function Yaml-ToJson() {
    Log-Debug "yaml2json --pretty --indentation 2" $Args

    yaml2json --pretty --indentation 2 $Args
}

function Yaml-FromJson() {
    Log-Debug "json2yaml --depth 64 --indentation 2" $Args

    json2yaml --depth 64 --indentation 2 $Args
}
上一篇 : [PowerShell] Help
下一篇 : [PowerShell] Hyper-V