Open13

Powershell で個人的によく使うあれこれ

Max0n_1027Max0n_1027

batファイルからPowerShellを実行する

  • 管理者権限なしの場合
@powershell -NoProfile -ExecutionPolicy RemoteSigned "$s=[scriptblock]::create((gc \"%~f0\"|?{$_.readcount -gt 1})-join\"`n\");&$s "%~dp0 %*&goto:eof
  • 管理者権限ありの場合
@echo off
for /f "tokens=3 delims=\ " %%i in ('whoami /groups^|find "Mandatory"') do set LEVEL=%%i
if NOT "%LEVEL%"=="High" (powershell -NoProfile -ExecutionPolicy Bypass  -Command "Start-Process %~f0 -Verb runas"&exit)
powershell -NoProfile -ExecutionPolicy RemoteSigned "$s=[scriptblock]::create((gc \"%~f0\"|?{$_.readcount -gt 4})-join\"`n\");&$s "%~dp0 %*&goto:eof

参考

https://hitoriit.blog/archives/141

Max0n_1027Max0n_1027

PowerShellでインストール済みプログラムの取得

$AppName = "hoge"
Get-WmiObject Win32_Product | Where-Object{$_.Name -eq $AppName)
Max0n_1027Max0n_1027

管理者権限に昇格して現在のスクリプトを実行

if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole("Administrators")) { Start-Process powershell.exe "-File `"$PSCommandPath`"" -Verb RunAs; exit }

参考

https://correct-log.com/powershell_auto_admin/

Max0n_1027Max0n_1027

管理者権限で実行されているか確認する関数

function IsAdmin(){
    $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
    return $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
Max0n_1027Max0n_1027

一時フォルダーにPowershellセッションを保存する

素のStart-Transcriptでは、「トランスクリプトが開始されました。出力ファイル:␣<FilePath>」の形式でパスがもどってくるので、-Split 演算子でファイルパスのみ戻すように作成

[string]$transPath=((Start-Transcript -OutputDirectory $env:TEMP) -Split " ")[1]

Get-Item $transPath | Format-Table

<#プログラムを記述#>

Stop-Transcript | Out-Null

実行結果(例)

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2022/10/18      6:45           1616 PowerShell_transcript.<HostName>.LZxPG2qs.20221018064537.txt
Max0n_1027Max0n_1027

ハッシュ値を求める関数

標準のGet-FileHashでは文字列のハッシュ値を求められないため

function Script:Get-HashValue {
    param(
        [parameter(mandatory = $true)][string]$text,
        [ValidateSet("SHA1", "SHA256", "SHA384", "SHA512", "MACTripleDES", "MD5", "RIPEMD160")][string]$Algorithm = "SHA256",
        [uint32]$stretch = 1
    ) 
    if ($stretch -ne 0) {
        $stringAsStream = [System.IO.MemoryStream]::new()
        $writer = [System.IO.StreamWriter]::new($stringAsStream)
        $writer.write($text)
        $writer.Flush()
        $stringAsStream.Position = 0
        return Get-HashValue -text ([string](Get-FileHash -InputStream $stringAsStream -Algorithm $Algorithm).Hash) -Algorithm $Algorithm -stretch ($stretch - 1)
    }
    else {
        return $text
    }
}

https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.utility/get-filehash?view=powershell-7.3

Max0n_1027Max0n_1027

Base64 エンコード・デコード

function ConvertTo-Base64 ([parameter(mandatory = $true)][string]$text) {
    $byte = ([System.Text.Encoding]::Default).GetBytes($text)
    return [Convert]::ToBase64String($byte)
}

function ConvertFrom-Base64 ([parameter(mandatory = $true)][string]$Base64) {
    $byte = [System.Convert]::FromBase64String($Base64)
    return [System.Text.Encoding]::Default.GetString($byte)
}

$text = "Hello World!!"
$base64 = Convertto-Base64 -text $text
$res = ConvertFrom-Base64 -Base64 $base64

Write-Host "変換前:$($text),Base64:$($base64),変換後:$($res)"
# > Hello World!!,Base64:SGVsbG8gV29ybGQhIQ==,変換後:Hello World!!
Max0n_1027Max0n_1027

選択肢プロンプトを呼び出す関数

function Invoke-ChoicePrompt {
    <#
    .SYNOPSIS
    コンソール上で選択肢プロンプトを呼び出す
    .PARAMETER ChoiceDescriptions
    以下のオブジェクトが含まれる配列データを渡す。
    [PSCustomObject]@{
        label       = Mandatory
        helpMessage = Optional
    }
    #>
    param([parameter(Mandatory,	HelpMessage = "[PSCustomObject]@{label,helpMessage}")][array]$ChoiceDescriptions,
        [string]$title,
        [string]$message,
        [int]$Default
    )
    $ChoiceDescription = @()
    $ChoiceDescriptions | ForEach-Object { $ChoiceDescription += New-Object System.Management.Automation.Host.ChoiceDescription($_.label, $_.helpMessage) }
    return $host.ui.PromptForChoice($title, $message, $ChoiceDescription, $Default)
}

function New-ChoiceDescription {
    [Alias("ChoDesc")]
    param (
        [parameter(Mandatory)][string]$label,
        [string]$helpMessage
    )
    return [PSCustomObject]@{
        label       = $label
        helpMessage = $helpMessage
    }
}

$result = Invoke-ChoicePrompt -ChoiceDescriptions @((ChoDesc "はい(&Y)" -helpMessage "次の処理を実行します。"), (ChoDesc "いいえ(&N)" -helpMessage "処理を実行しません。"))

Max0n_1027Max0n_1027

メッセージボックスを呼び出す関数

function Invoke-MessageBox {
    param (
        [parameter(mandatory)][string]$text,
        [string]$caption = "",
        [ValidateSet("OK" , "OKCancel", "AbortRetryIgnore", "YesNoCancel", "YesNo", "RetryCancel", "CancelTryContinue")][string]$button = "OK",
        [ValidateSet("None" , "Stop", "Question", "Exclamation", "Information")][string]$icon = "None",
        [ValidateSet("Button1" , "Button2", "Button3", "Button4")][string]$defaultButton = "Button1"
    )
    Add-Type -Assembly System.Windows.Forms
    return [System.Windows.Forms.MessageBox]::Show($text, $caption, $button, $icon, $defaultButton)
}
Max0n_1027Max0n_1027

インプットボックスを呼び出す関数

function Invoke-InputBox {
    param (
        [parameter(mandatory)][string]$Prompt,
        [string]$Title = " ",
        [string]$DefaultResponse
    )
    [void][System.Reflection.Assembly]::Load("Microsoft.VisualBasic, Version=8.0.0.0, Culture=Neutral, PublicKeyToken=b03f5f7f11d50a3a")
   return [Microsoft.VisualBasic.Interaction]::InputBox($Prompt, $Title, $DefaultResponse)
}
Max0n_1027Max0n_1027

ランダムな文字列を作成する関数

function Get-RandomText {
    param (
        [int]$length = 10,
        [switch]$upperCase,
        [switch]$lowercase,
        [switch]$number,
        [switch]$symbols,
        [switch]$duplicated
    )
    
    if (($upperCase -or $lowercase -or $number -or $symbols) -eq $false) {
        $upperCase = $true
        $lowercase = $true
        $number = $true
        $symbols = $true
    }
    if ($upperCase) { $asciiTable += [char[]](65..90) }
    if ($lowercase) { $asciiTable += [char[]](97..122) }
    if ($number) { $asciiTable += [char[]](48..57) }
    if ($symbols) { $asciiTable += [char[]](33, 47) + [char[]](58..64) + [char[]](91..96) + [char[]](123..126) }
    
    if ($duplicated) { return [string][char[]]((1..$length) | ForEach-Object { $asciiTable  | Get-Random } ) -replace " " , "" }
    else { 
        if ($asciiTable.Length -ge $length) { return [string][char[]]($asciiTable | Get-Random -Count $length) -replace " " , "" }
        else { Write-Error -Message "Length Is Too Long." }
    }
}
Max0n_1027Max0n_1027

トースト通知を作成する関数

Function Show-Toast {
    [CmdletBinding()]
    PARAM (
        [String]$title = "",
        [String]$message = "",
        [String]$detail = "",
        [String]$icon = "",
        [String]$hero = "",
        [string]$uri = "",
        [string]$appID = '{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\WindowsPowerShell\v1.0\powershell.exe'
    )
    if ($detail -ne "" ) { $detail = "<text>$($detail)</text>" } 
    if ($icon -ne "" ) { if (Test-Path $icon ) { $icon = "<image placement=`"appLogoOverride`" hint-crop=`"circle`" src=`"$($icon)`"/>" } }
    if ($hero -ne "" ) { if (Test-Path $hero ) { $hero = "<image placement=`"hero`" hint-crop=`"circle`" src=`"$($hero)`"/>" } }
    if ($uri -ne "" ) { $uri = "activationType=`"protocol`" launch=`"$($uri)`"" } 
    [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
    [Windows.UI.Notifications.ToastNotification, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
    [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] | Out-Null
    $content = @"
<?xml version="1.0" encoding="utf-8"?>
<toast $($uri) >
    <visual>
        <binding template="ToastGeneric">
            <text>$($title)</text>
            <text>$($message)</text>
            $($detail)
            $($icon)
            $($hero)
        </binding>
    </visual>
</toast>
"@
    $xml = New-Object Windows.Data.Xml.Dom.XmlDocument
    $xml.LoadXml($content)
    $toast = New-Object Windows.UI.Notifications.ToastNotification $xml
    [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($appid).Show($toast)
}
Max0n_1027Max0n_1027

進行状況バーを作成する関数

Function Show-ProgressToast {
    [CmdletBinding()]
    PARAM (
        [String]$title,
        [String]$message,
        [String]$progressTitle,
        [String]$tag = (New-Guid).Guid ,
        [String]$group =  (New-Guid).Guid ,
        [string]$appID = '{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\WindowsPowerShell\v1.0\powershell.exe'
    )

    $meta = [PSCustomObject]@{
        Tag   = $tag
        Group = $group
        AppID = $appID
    }

    [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
    [Windows.UI.Notifications.ToastNotification, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
    [Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] | Out-Null
    $content = @"
<?xml version="1.0" encoding="utf-8"?>
<toast>
    <visual>
        <binding template="ToastGeneric">
            <text>$($title)</text>
            <text>$($message)</text>
            <progress value="{progressValue}" title="{progressTitle}" valueStringOverride="{progressValueString}" status="{progressStatus}" />
        </binding>
    </visual>
</toast>
"@

    $xml = New-Object Windows.Data.Xml.Dom.XmlDocument
    $xml.LoadXml($content)
    $toast = New-Object Windows.UI.Notifications.ToastNotification $xml
    $toast.Tag = $meta.Tag
    $toast.Group = $meta.Group
    $toastData = New-Object 'system.collections.generic.dictionary[string,string]'
    $toastData.add("progressTitle", $progressTitle)
    $toastData.add("progressValue", "")
    $toastData.add("progressValueString", "")
    $toastData.add("progressStatus", "")
    $toast.Data = [Windows.UI.Notifications.NotificationData]::new($toastData)
    $toast.Data.SequenceNumber = 1
    [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($meta.AppID).Show($toast)
    return $meta
}

Function Update-ProgessToast {
    [CmdletBinding()]
    PARAM (
        [Parameter(Mandatory)]$meta,
        [Parameter(Mandatory)][String] $value,
        [Parameter(Mandatory)][String] $message,
        [Parameter(Mandatory)][String] $status
    )

    $toastData = New-Object 'system.collections.generic.dictionary[string,string]'
    $toastData.add("progressValue", $value)
    $toastData.add("progressValueString", $message)
    $toastData.add("progressStatus", $status)
    $progressData = [Windows.UI.Notifications.NotificationData]::new($toastData)
    $progressData.SequenceNumber = 2

    [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($meta.AppID).Update($progressData, $meta.Tag , $meta.Group) | Out-Null

}