Open5

PowerShell Tips

fj68fj68

ショートカットを作成する

コマンドレットとしては用意されていないので、WScript.ShellCreateShortcutを使う。
ファイル名の拡張子が.lnkならWshShortcut(ローカルショートカット)、.urlならWshUrlShortcut(インターネットショートカット)になる。

Shortcut.psm1
enum WindowStyle {
  Active = 1
  Maximize = 3
  Minimize = 7
}

function New-Shortcut {
    param(
        [Parameter(Position=0, Mandatory, ValueFromPipelineByPropertyName)]
        [string] $TargetPath,
        [Parameter(Position=1, Mandatory, ValueFromPipelineByPropertyName)]
        [string] $Name,
        [Parameter(ValueFromPipelineByPropertyName)]
        $WindowStyle,
        [Parameter(ValueFromPipelineByPropertyName)]
        $WorkingDirectory,
        [Parameter(ValueFromPipelineByPropertyName)]
        [string] $HotKey,
        [Parameter(ValueFromPipelineByPropertyName)]
        [string] $Description,
        [Parameter(ValueFromPipelineByPropertyName)]
        $IconLocation
    )
    $sh = New-Object -ComObject WScript.Shell
    $ln = $sh.CreateShortcut($Name)
    $ln.TargetPath = $TargetPath
    if ($null -ne $WindowStyle) {
        $ln.WindowStyle = $WindowStyle
    }
    if ($null -ne $WorkingDirectory) {
        $ln.WorkingDirectory = $WorkingDirectory
    }
    if (-not [string]::IsNullOrEmpty($HotKey)) {
        $ln.HotKey = $HotKey
    }
    if (-not [string]::IsNullOrEmpty($Description)) {
        $ln.Description = $Description
    }
    if ($null -ne $IconLocation) {
        $ln.IconLocation = $IconLocation
    }
    $ln.Save()
}

https://learn.microsoft.com/ja-jp/troubleshoot/windows-client/admin-development/create-desktop-shortcut-with-wsh

fj68fj68

UUIDv4を作成する

Uuid.psm1
function New-UUIDv4 {
    -join ("xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".ToCharArray() | % {
        switch ($_) {
            'x' { return (Get-Random -Maximum 16).ToString('x') }
            'y' { return ((Get-Random -Maximum 16) + 8).ToString('x') }
            default { return $_ }
        }
    })
}
fj68fj68

CSVとJSON

Import-Jsonがない

Windows 10に標準インストールされているPowerShell環境はかなり古いため、Import-Jsonがない。
が、しかし、ConvertFrom-JsonConvertTo-Jsonがあるため

# JSONファイル読み込み
Get-Content sample.json | ConvertFrom-Json
# JSONファイル出力
ConvertTo-Json $data | Out-File sample.json

でなんとかなる。

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertfrom-json?view=powershell-7.5

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertto-json?view=powershell-7.5

Shift_JISの扱い

Windows環境ならGet-Content-Encoding Oemを指定するのが一番楽。

Get-Content -Encoding Oem file_in_sjis.json | ConvertFrom-Json

Export-Csvで謎の型情報が出る

PowerShell 6.0以前はExport-Csvで出力されるファイルにはデフォルトで型情報が付与されていて、型情報なしで出力するには-NoTypeInformationオプションを付ける必要があった。
その後、型情報なしで出力する動作がデフォルト動作として変更された。
後方互換性のために-NoTypeInformationオプションは残されているため、どのバージョンのPowerShellであっても基本的にExport-Csvには-NoTypeInformationを付けておくとよい。

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/export-csv?view=powershell-7.5#-notypeinformation

タブ区切りCSVを扱う

Import-Csv -Delimiter "`t"でタブ区切りのCSV(TSVとも)を読み込める。

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/import-csv?view=powershell-7.5#-delimiter

fj68fj68

エスケープシーケンス

Windows 10以降の標準ターミナル(conhost.exe)やPowerShellのターミナル(powershell.exe)ではエスケープシーケンスによる文字色の変更などがサポートされている。

https://qiita.com/PruneMazui/items/8a023347772620025ad6

有効化する

一部環境ではデフォルトで無効になっているので、レジストリのHKEY_CURRENT_USER\ConsoleにDWORD値VirtualTerminalLevelを追加し、その値を1にする必要がある。

Set-ItemProperty -Path "HKCU:\Console" -Name "VirtualTerminalLevel" -Value 1 -Type DWord

文字色を変える

エスケープ + [31mで文字色を赤にし、エスケープ + [0mで文字色を元にもどしている。
PowerShell 6以降であればエスケープ($([char]27))は`eでもOK。

Write-Host "$([char]27)[31mThis is a red text.$([char]27)[0m"
fj68fj68

WPFでGUI

https://qiita.com/HrmsTrsmgs/items/1eca0516bd8c690872dc

AttachConsole

C#コードですが、csc /target:winexeでコンパイルした実行ファイルでもAttachConsoleを使用すれば標準出力へデータを流せます。

winexe.exe
using System;
using System.Runtime.InteropServices;

public class Win32
{
    public static int ATTACH_PARENT_PROCESS = -1;

    [DllImport("kernel32.dll")]
    public static extern bool AttachConsole(int dwProcessId);
}

public class Program
{
    [STAThread]
    public static void Main()
    {
        if (Win32.AttachConsole(Win32.ATTACH_PARENT_PROCESS))
        {
            using (var stdout = new StreamWriter(Console.OpenStandardOutput(), Encoding.GetEncoding("shift-jis")))
            {
                Console.SetOut(stdout);
                Consolw.WriteLine("{\"hello\": "world!\\n\"}");
            }
        }
    }
}

GUIアプリの終了を待つ

Start-Process-Waitを使うとGUIアプリの終了を待つことができます。

さらに、-RedirectStandardOutputを使えば標準出力をファイルへリダイレクトできるのでデータの受け渡しが可能です。

$tmp = New-TemporaryFile
Start-Process winexe.exe -Wait -RedirectStandardOutput $tmp
$r = Get-Content -Encoding Oem $tmp | ConvertFrom-Json
Remove-Item $tmp