💳
自作Functionを半自動でPowerShellプロファイルに定義するコード
概要
こちらの記事でデータ型を確認できるFunctionを自作しました。
このような自作Functionは、PowerShellのプロファイルに定義する事で簡単に呼び出すことができます。
ただ、環境が変わる度にPowerShellのプロファイルを定義する必要があった為、面倒に感じていました。
この問題を解決するため、今回は自作したFunctionを読み込み、PowerShellのプロファイルに半自動で定義するコードを作成しました。
なお、自作したFunctionを読み込む方法は、ハードコーディングしたコードを読み込む方法 と 専用フォルダー配下のps1ファイルを読み込む方法 の2通りで準備しました。
この記事のターゲット
- PowerShellユーザーの方
- 自作したFunctionを半自動でPowerShellプロファイル(
$PROFILE
)に定義したい方
環境
$PSVersionTable
PS C:\Users\"ユーザー名"> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.19041.4170
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.19041.4170
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
PS C:\Users\"ユーザー名">
半自動でPowerShellプロファイルを作成し自作Functionを定義するコード
冒頭に記載した通り、ハードコーディングした自作Function と 専用フォルダー配下にあるps1ファイル内の自作Function の2つから読み込み、PowerShellのプロファイルに定義します。
各々の用途にあわせてカスタマイズしてください。
テンプレート
# PowerShellプロファイルのヘッダー
[System.String[]]$header =
@"
#################################################################################
# PowerShellプロファイル
# ($($PROFILE))
#
#################################################################################
"@
# ハードコーディングしている自作Function
[System.String[]]$ps_source =
@'
【ここに自作Functionをハードコーディングする】
'@ -split "`r`n"
# プロファイル用のPowerShellスクリプト($PROFILE)がない場合は、新規作成
if (-Not(Test-Path $PROFILE)) {
# LF変換
$header = $header -Replace "`r`n", "`n"
# 文字コードは UTF-8 BOM付き で新規作成
$utf8Encoding = New-Object System.Text.UTF8Encoding $true
[System.IO.File]::WriteAllText($PROFILE, $header, $utf8Encoding)
}
# プロファイル が UTF-8 BOM付き であるか確認
$UTF8_BOM = [System.Byte[]](0xEF,0xBB,0xBF)
[System.Byte[]]$first_3bytes = (Get-Content -Path $PROFILE -Encoding Byte -TotalCount 3)
if (-Not($null -eq (Compare-Object $first_3bytes $UTF8_BOM -SyncWindow 0))) {
Write-Host "プロファイルのPowerShellスクリプト[$PROFILE]の文字コードが「UTF-8 BOM付き」ではありません。" -ForegroundColor Red
Write-Host "処理を中断します。" -ForegroundColor Red
return
}
# ハードコーディングした自作Function($ps_source)をプロファイルに追記
[System.String]$name = ''
[System.Boolean]$is_skip = $false
$func_lines = $ps_source -split "`n" | Where-Object { $_ -match "^Function " }
if ($func_lines.Count -gt 0) {
foreach ($line in $func_lines) {
$name = ($line -split ' ' | Select-Object -First 2)
If (Select-String -Path $PROFILE -Pattern $name) {
Write-Host 'ハードコーディングしたコード($ps_source)のFunctionがプロファイルに定義済みです。ハードコーディングした自作Functionの追記処理はスキップします。'
Write-Host "(プロファイルに登録済みのFunction名: [$name])"
$is_skip = $true
break
}
}
# ハードコーディングした自作Functionを追記
if (-Not($is_skip)) {
# LF変換
$ps_source = $ps_source -Replace "`r`n", "`n"
Add-Content -Path $PROFILE -Value $ps_source
}
}
# ps1ファイルを格納する専用フォルダーがない場合は、フォルダーを作成
[System.String]$psfolder_path = "$PROFILE\..\user-defined-ps"
if (-Not(Test-Path $psfolder_path)) {
# フォルダーを作成
New-Item -Path $psfolder_path -ItemType 'directory' -Force > $null
}
$psfolder_path = (Convert-Path $psfolder_path)
# 専用フォルダー内の自作Functionをプロファイルに追記
$name = ''
$is_skip = $false
# 専用フォルダー配下にps1ファイルがない場合は、この処理が最終処理となるため早期リターン
if (-Not(Test-Path "$psfolder_path\*.ps1")) {
Write-Host "専用フォルダー [$psfolder_path] にps1ファイルがありません。処理を終了します。"
return
}
[System.String]$psfolder_source = (Get-Content "$psfolder_path\*.ps1" -Raw)
$func_lines = $psfolder_source -split "`n" | Where-Object { $_ -match "^Function " }
if ($func_lines.Count -gt 0) {
foreach ($line in $func_lines) {
$name = ($line -split ' ' | Select-Object -First 2)
If (Select-String -Path $PROFILE -Pattern $name) {
Write-Host '専用フォルダー内のFunctionがプロファイルに定義済みです。専用フォルダーにある自作Functionの追記処理はスキップします。。'
Write-Host "(プロファイルに登録済みのFunction名: [$name])"
$is_skip = $true
break
}
}
# 専用フォルダーにある自作Functionの追記
if (-Not($is_skip)) {
# LF変換
$psfolder_source = $psfolder_source -Replace "`r`n", "`n"
Add-Content -Path $PROFILE -Value $psfolder_source
}
}
実例(実際に私が作成したFunctionをハードコーディングした例)
コード(実際に私が作成したFunctionをハードコーディングした例)
# PowerShellプロファイルのヘッダー
[System.String[]]$header =
@"
#################################################################################
# PowerShellプロファイル
# ($($PROFILE))
#
#################################################################################
"@
# ハードコーディングしている自作Function
[System.String[]]$ps_source =
@'
#################################################################################
# 処理名 | VerificationEnv
# 機能 | PowerShell環境チェック
# | 参考情報:https://zenn.dev/haretokidoki/articles/fac8e50fbe9dcd
#--------------------------------------------------------------------------------
# 戻り値 | MESSAGECODE(enum)
# 引数 | なし
#################################################################################
# エラーコード enum設定
Add-Type -TypeDefinition @"
public enum MESSAGECODE {
Successful = 0,
Abend,
Cancel,
Error_NotCore,
Error_NotSupportedVersion,
Error_NotWindows
}
"@
Function VerificationEnv {
[MESSAGECODE]$return_code = [MESSAGECODE]::Successful
# 環境情報を取得
[System.Collections.Hashtable]$ps_ver = $PSVersionTable
# 環境の判定:Coreではない場合(5.1だと'Desktop'となる)
if ($ps_ver.PSEdition -ne 'Core') {
$return_code = [MESSAGECODE]::Error_NotCore
Write-Host 'Core(6.0以降)の環境ではない' -ForegroundColor Red
}
# 環境の判定:メジャーバージョンが7より小さい場合
elseif ($ps_ver.PSVersion.Major -lt 7) {
$return_code = [MESSAGECODE]::Error_NotSupportedVersion
Write-Host 'Core(6.0以降)の環境だが、7以上 の環境ではない' -ForegroundColor Red
}
# 環境の判定:Windows OSではない場合(PowerShell Coreのみ使用できる自動変数)
elseif (-Not($IsWindows)) {
$return_code = [MESSAGECODE]::Error_NotWindows
Write-Host 'Core(6.0以降)の環境で、かつ 7以上 の環境だが、Windows OS の環境ではない' -ForegroundColor Red
}
else {
Write-Host 'Core(6.0以降)の環境で、かつ 7以上 の環境、Windows OS の環境である'
}
return $return_code
}
#################################################################################
# 処理名 | Get-Datatype
# 機能 | 変数のデータ型を確認
# | 参考情報:https://zenn.dev/haretokidoki/articles/1632e92c37ea98
#--------------------------------------------------------------------------------
# 戻り値 | データ型を表示(項目1:BaseType、項目2:Type)
# 引数 | $variable 調査対象の変数
#################################################################################
Function Get-Datatype {
Param (
[Parameter(Mandatory=$true)]$variable
)
# 文字列配列を宣言
[System.String[]]$rowdata = @(
$variable.GetType().BaseType.FullName, # 変数のベースタイプ
$variable.GetType().FullName # 変数のデータ型
)
# PSCustomObjectで項目名を設定
$types_table = [PSCustomObject]@{
BaseType = $rowdata[0]
DataType = $rowdata[1]
}
# コンソールで表示
$types_table | Format-Table -Property BaseType, DataType -AutoSize -Wrap
}
#################################################################################
# 処理名 | Test-IsAdmin
# 機能 | PowerShellが管理者として実行しているか確認
# | 参考情報:https://zenn.dev/haretokidoki/articles/67788ca9b47b27
#--------------------------------------------------------------------------------
# 戻り値 | Boolean(True: 管理者権限あり, False: 管理者権限なし)
# 引数 | -
#################################################################################
Function Test-IsAdmin {
$win_id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$win_principal = new-object System.Security.Principal.WindowsPrincipal($win_id)
$admin_permission = [System.Security.Principal.WindowsBuiltInRole]::Administrator
return $win_principal.IsInRole($admin_permission)
}
#################################################################################
# 処理名 | GetPsCharcode
# 機能 | PowerShellコンソールの文字コードを取得
# | 参考情報:https://zenn.dev/haretokidoki/articles/67788ca9b47b27
#--------------------------------------------------------------------------------
# 戻り値 | ps_charcode[]
# | - 項目01 文字エンコードを指定できるコマンドレットの既定値
# | - 項目02 PowerShellから外部プログラムに渡す文字エンコードの設定
# | - 項目01 PowerShellのコンソールに出力する文字エンコードの設定
# 引数 | -
#################################################################################
Function GetPsCharcode {
[System.String[]]$ps_charcode = @()
$ps_charcode = @(
# 文字エンコードを指定できるコマンドレットの既定値
($PSDefaultParameterValues['*:Encoding']),
# PowerShellから外部プログラムに渡す文字エンコードの設定
($global:OutputEncoding).WebName,
# PowerShellのコンソールに出力する文字エンコードの設定
([console]::OutputEncoding).WebName
)
return $ps_charcode
}
#################################################################################
# 処理名 | ChangeWindowTitle
# 機能 | PowerShellウィンドウのタイトル変更(文字コードとPowerShellの管理者権限有無を追加)
# | 参考情報:https://zenn.dev/haretokidoki/articles/67788ca9b47b27
#--------------------------------------------------------------------------------
# 戻り値 | -
# 引数 | -
#################################################################################
# PowerShellウィンドウのタイトル変更
Function ChangeWindowTitle {
# 区切り文字の設定
[System.String]$pos1 = '|'
[System.String]$pos2 = ';'
# 現在のタイトルを取得
[System.String]$title = $Host.UI.RawUI.WindowTitle
[System.String]$base_title = $title
# 既にこのFunctionでタイトル変更している場合、一番左にある文字列を抽出
[System.String[]]$title_array = $title.Split($pos1)
if ($title_array.Length -ne 0) {
$base_title = ($title_array[0]).TrimEnd()
}
# 現在の文字コードを取得しタイトルに追加
[System.String[]]$ps_charcode = GetPsCharcode
[System.String]$change_title = $base_title
if (Test-IsAdmin) {
# 管理者として実行している場合
$change_title = $base_title + " $pos1 " +
"DefaultParameter='$($ps_charcode[0])'" + " $pos2 " +
"GlobalEncoding='$($ps_charcode[1])'" + " $pos2 " +
"ConsoleEncoding='$($ps_charcode[2])'" + " $pos2 " +
"#Administrator"
}
else {
# 管理者として実行していない場合
$change_title = $base_title + " $pos1 " +
"DefaultParameter='$($ps_charcode[0])'" + " $pos2 " +
"GlobalEncoding='$($ps_charcode[1])'" + " $pos2 " +
"ConsoleEncoding='$($ps_charcode[2])'" + " $pos2 " +
"#Not_Administrator"
}
$Host.UI.RawUI.WindowTitle = $change_title
# 完了メッセージ
Write-Host 'タイトルに“文字コード”と“管理者権限の有無”の情報を追加しました。' -ForegroundColor Cyan
}
#################################################################################
# 処理名 | SetPsOutputEncoding
# 機能 | PowerShellにおける複数の文字コード設定を一括変更
# | 参考情報:https://zenn.dev/haretokidoki/articles/8946231076f129
#--------------------------------------------------------------------------------
# 戻り値 | -
# 引数 | $charcode(引数を省略した場合は、'reset_encoding'で設定)
# | - 'utf8' : UTF-8に設定
# | - 'sjis' : Shift-JISに設定
# | - 'ascii' : US-ASCIIに設定
# | - 'rm_encoding' : デフォルトパラーメーターを削除
# | - 'reset_encoding': 規定値に戻す
#################################################################################
Function SetPsOutputEncoding {
Param (
[System.String]$charcode = 'reset_encoding'
)
switch ($charcode) {
# 文字エンコードをUTF8に設定する
'utf8' {
$PSDefaultParameterValues['*:Encoding'] = 'utf8'
$global:OutputEncoding = [System.Text.Encoding]::UTF8
[console]::OutputEncoding = [System.Text.Encoding]::UTF8
}
# 文字エンコードをShift JIS(SJIS)に設定する
'sjis' {
# $PSDefaultParameterValues['*:Encoding'] = 'default'について
# この設定はCore以外(5.1以前)の環境でのみShift JISで設定される。
# Core環境のデフォルト値は、UTF-8でありUTF-8で設定されてしまう。
# また、Shift JISのパラメーターも存在しない為、Core環境でShift JISの設定は不可となる。
$PSDefaultParameterValues['*:Encoding'] = 'default'
$global:OutputEncoding = [System.Text.Encoding]::GetEncoding('shift_jis')
[console]::OutputEncoding = [System.Text.Encoding]::GetEncoding('shift_jis')
}
# 文字エンコードをASCIIに設定する
'ascii' {
$PSDefaultParameterValues.Remove('*:Encoding')
$global:OutputEncoding = [System.Text.Encoding]::ASCII
[console]::OutputEncoding = [System.Text.Encoding]::ASCII
}
# デフォルトパラメータの文字エンコード指定を解除する
'rm_encoding' {
$PSDefaultParameterValues.Remove('*:Encoding')
}
# 文字エンコード設定を初期状態に戻す
'reset_encoding' {
$PSDefaultParameterValues.Remove('*:Encoding')
If ($PSVersionTable.PSEdition -eq 'Core') {
# Core の場合
$global:OutputEncoding = [System.Text.Encoding]::UTF8
[console]::OutputEncoding = [System.Text.Encoding]::GetEncoding('shift_jis')
}
else {
# Core 以外の場合(PowerShell 5.1 以前)
$global:OutputEncoding = [System.Text.Encoding]::ASCII
[console]::OutputEncoding = [System.Text.Encoding]::GetEncoding('shift_jis')
}
}
}
# タイトルの表示切替Function呼び出し
ChangeWindowTitle
}
#################################################################################
# 処理名 | Get-PsEncoding
# 機能 | PowerShellでファイルの文字コードを判定
# | 参考情報:https://zenn.dev/haretokidoki/articles/962a7fc6c51b47
#--------------------------------------------------------------------------------
# 戻り値 | -
# 引数 | $targetfile 対象ファイル
#################################################################################
Function Get-PsEncoding {
Param (
[Parameter(Mandatory=$true)][System.String]$targetfile
)
$stream_reader = [System.IO.StreamReader] $targetfile
$profile_encoding = $stream_reader.CurrentEncoding
$stream_reader.Close()
Write-Host "EncodingName: [$($profile_encoding.EncodingName)]"
}
#################################################################################
# 処理名 | Check-BOMStatus
# 機能 | PowerShellでファイルの文字コードにおけるBOMを判定
# | 参考情報:https://zenn.dev/haretokidoki/articles/962a7fc6c51b47
#--------------------------------------------------------------------------------
# 戻り値 | -
# 引数 | $targetfile 対象ファイル
#################################################################################
Function Check-BOMStatus {
Param (
[Parameter(Mandatory=$true)][System.String]$targetfile
)
if (-Not (Test-Path $targetfile)) {
Write-Host 'The target file does not exist.' -ForegroundColor Red
return
}
# BOMのバイトシーケンス
$UTF7_BOM1 = [System.Byte[]](0x2B,0x2F,0x76,0x38)
$UTF7_BOM2 = [System.Byte[]](0x2B,0x2F,0x76,0x39)
$UTF7_BOM3 = [System.Byte[]](0x2B,0x2F,0x76,0x2B)
$UTF7_BOM4 = [System.Byte[]](0x2B,0x2F,0x76,0x2F)
$UTF8_BOM = [System.Byte[]](0xEF,0xBB,0xBF)
$UTF16BE_BOM = [System.Byte[]](0xFE,0xFF)
$UTF16LE_BOM = [System.Byte[]](0xFF,0xFE)
$UTF32BE_BOM = [System.Byte[]](0x00,0x00,0xFE,0xFF)
$UTF32LE_BOM = [System.Byte[]](0xFF,0xFE,0x00,0x00)
# 先頭行をバイトで読み込み先頭から3バイト分のデータを取得
[System.Byte[]]$first_4bytes = (Get-Content -Path $targetfile -Encoding Byte -TotalCount 4)
[System.Byte[]]$first_3bytes = $first_4bytes[0..2]
[System.Byte[]]$first_2bytes = $first_4bytes[0..1]
# 先頭バイトでBOM付きか判定
# UTF-7
if (($null -eq (Compare-Object $first_4bytes $UTF7_BOM1 -SyncWindow 0)) -Or
($null -eq (Compare-Object $first_4bytes $UTF7_BOM2 -SyncWindow 0)) -Or
($null -eq (Compare-Object $first_4bytes $UTF7_BOM3 -SyncWindow 0)) -Or
($null -eq (Compare-Object $first_4bytes $UTF7_BOM4 -SyncWindow 0))) {
Write-Host "[$($targetfile)] is UTF-7 BOM."
}
# UTF-8
elseif ($null -eq (Compare-Object $first_3bytes $UTF8_BOM -SyncWindow 0)) {
Write-Host "[$($targetfile)] is UTF-8 BOM."
}
# UTF-16 BE
elseif ($null -eq (Compare-Object $first_2bytes $UTF16BE_BOM -SyncWindow 0)) {
Write-Host "[$($targetfile)] is UTF-16 BE BOM."
}
# UTF-16 LE
elseif ($null -eq (Compare-Object $first_2bytes $UTF16LE_BOM -SyncWindow 0)) {
Write-Host "[$($targetfile)] is UTF-16 LE BOM."
}
# UTF-32 BE
elseif ($null -eq (Compare-Object $first_4bytes $UTF32BE_BOM -SyncWindow 0)) {
Write-Host "[$($targetfile)] is UTF-32 BE BOM."
}
# UTF-32 LE
elseif ($null -eq (Compare-Object $first_4bytes $UTF32LE_BOM -SyncWindow 0)) {
Write-Host "[$($targetfile)] is UTF-32 LE BOM."
}
else {
Write-Host "[$($targetfile)] is not BOM." -ForegroundColor Red
}
}
#################################################################################
# 処理名 | Get-PyEncoding
# 機能 | Pythonでファイルの文字コードを判定
# | 参考情報:https://zenn.dev/haretokidoki/articles/aea5b45679d966
#--------------------------------------------------------------------------------
# 戻り値 | -
# 引数 | $targetfile 対象ファイル
#################################################################################
Function Get-PyEncoding {
Param (
[Parameter(Mandatory=$true)][System.String]$targetfile
)
# python インストール確認
if (-Not(Get-Command 'python' -ErrorAction SilentlyContinue)) {
Write-Host 'Python is not install.' -ForegroundColor Red
return
}
# 存在チェック
if (-Not(Test-Path $targetfile)) {
Write-Host "[$targetfile] does not exist." -ForegroundColor Red
return
}
# 絶対パスに変換
[System.String]$fullpath_targetfile = (Convert-Path $targetfile)
# データ種類のチェック
if (-Not(Test-Path $fullpath_targetfile -PathType Leaf)) {
Write-Host "[$fullpath_targetfile] is not a file." -ForegroundColor Red
return
}
# Pythonスクリプトのコード
[System.String[]]$py_source =
@"
import subprocess
import sys
# chardet がインストールされていない場合はインストールしてからインポート
try:
import chardet
except ImportError:
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'chardet', '--user'])
import chardet
# 文字コードを判定するFunction
def determine_encoding(file_path):
with open(file_path, 'rb') as file:
raw_data = file.read()
result = chardet.detect(raw_data)
print(f"Detected encoding for [{file_path}] is {result['encoding']} with {result['confidence']*100}% confidence.")
# コマンドラインの引数を取得
file_path = sys.argv[1]
# 対象ファイルの文字列を判定
determine_encoding(file_path)
"@ -split "`r`n"
# Pythonスクリプトの準備
# Pythonスクリプトを格納するフォルダーがない場合は、新規作成
[System.String]$pyfolder_path = "$PROFILE\..\user-defined-py"
if (-Not(Test-Path $pyfolder_path)) {
New-Item -Path $pyfolder_path -ItemType 'directory' -Force > $null
}
$pyfolder_path = (Convert-Path $pyfolder_path)
# 今回実行するPythonスクリプトがない場合は、新規作成
[System.String]$pyscript_path = "$pyfolder_path\chardet_runner.py"
if (-Not(Test-Path $pyscript_path)) {
# なぜかLFコードのデータであるため、CRLFに変換
$py_source = $py_source -Replace "`n", "`r`n"
$utf8Encoding = New-Object System.Text.UTF8Encoding
[System.IO.File]::WriteAllText($pyscript_path, $py_source, $utf8Encoding)
}
# Pythonスクリプトの実行
try {
python $pyscript_path $fullpath_targetfile
}
catch {
Write-Host 'Python script execution error.'
return
}
}
'@ -split "`r`n"
# プロファイル用のPowerShellスクリプト($PROFILE)がない場合は、新規作成
if (-Not(Test-Path $PROFILE)) {
# LF変換
$header = $header -Replace "`r`n", "`n"
# 文字コードは UTF-8 BOM付き で新規作成
$utf8Encoding = New-Object System.Text.UTF8Encoding $true
[System.IO.File]::WriteAllText($PROFILE, $header, $utf8Encoding)
}
# プロファイル が UTF-8 BOM付き であるか確認
$UTF8_BOM = [System.Byte[]](0xEF,0xBB,0xBF)
[System.Byte[]]$first_3bytes = (Get-Content -Path $PROFILE -Encoding Byte -TotalCount 3)
if (-Not($null -eq (Compare-Object $first_3bytes $UTF8_BOM -SyncWindow 0))) {
Write-Host "プロファイルのPowerShellスクリプト[$PROFILE]の文字コードが「UTF-8 BOM付き」ではありません。" -ForegroundColor Red
Write-Host "処理を中断します。" -ForegroundColor Red
return
}
# ハードコーディングした自作Function($ps_source)をプロファイルに追記
[System.String]$name = ''
[System.Boolean]$is_skip = $false
$func_lines = $ps_source -split "`n" | Where-Object { $_ -match "^Function " }
if ($func_lines.Count -gt 0) {
foreach ($line in $func_lines) {
$name = ($line -split ' ' | Select-Object -First 2)
If (Select-String -Path $PROFILE -Pattern $name) {
Write-Host 'ハードコーディングしたコード($ps_source)のFunctionがプロファイルに定義済みです。ハードコーディングした自作Functionの追記処理はスキップします。'
Write-Host "(プロファイルに登録済みのFunction名: [$name])"
$is_skip = $true
break
}
}
# ハードコーディングした自作Functionを追記
if (-Not($is_skip)) {
# LF変換
$ps_source = $ps_source -Replace "`r`n", "`n"
Add-Content -Path $PROFILE -Value $ps_source
}
}
# ps1ファイルを格納する専用フォルダーがない場合は、フォルダーを作成
[System.String]$psfolder_path = "$PROFILE\..\user-defined-ps"
if (-Not(Test-Path $psfolder_path)) {
# フォルダーを作成
New-Item -Path $psfolder_path -ItemType 'directory' -Force > $null
}
$psfolder_path = (Convert-Path $psfolder_path)
# 専用フォルダー内の自作Functionをプロファイルに追記
$name = ''
$is_skip = $false
# 専用フォルダー配下にps1ファイルがない場合は、この処理が最終処理となるため早期リターン
if (-Not(Test-Path "$psfolder_path\*.ps1")) {
Write-Host "専用フォルダー [$psfolder_path] にps1ファイルがありません。処理を終了します。"
return
}
[System.String]$psfolder_source = (Get-Content "$psfolder_path\*.ps1" -Raw)
$func_lines = $psfolder_source -split "`n" | Where-Object { $_ -match "^Function " }
if ($func_lines.Count -gt 0) {
foreach ($line in $func_lines) {
$name = ($line -split ' ' | Select-Object -First 2)
If (Select-String -Path $PROFILE -Pattern $name) {
Write-Host '専用フォルダー内のFunctionがプロファイルに定義済みです。専用フォルダーにある自作Functionの追記処理はスキップします。。'
Write-Host "(プロファイルに登録済みのFunction名: [$name])"
$is_skip = $true
break
}
}
# 専用フォルダーにある自作Functionの追記
if (-Not($is_skip)) {
# LF変換
$psfolder_source = $psfolder_source -Replace "`r`n", "`n"
Add-Content -Path $PROFILE -Value $psfolder_source
}
}
この内容をPowerShellウィンドウで実行すると、ハードコーディングした自作Functionがプロファイルに反映され、
下記の結果が返ってきます。
なお、今回は専用フォルダー配下にps1ファイルは格納せずに実行しました。実行結果からも、その旨のメッセージが表示されています。
実際の実行結果(PowerShellウィンドウの結果)
専用フォルダー [D:\Documents\WindowsPowerShell\user-defined-ps] にps1ファイルがありません。処理を終了します。
PS C:\Users\"ユーザー名">
下記が実行後、ハードコーディングしたコードが反映されたプロファイルの中身。
なお、プロファイルの内容はリアルタイムで読み込みされません。PowerShellウィンドウを起動する時にプロファイルが読み込まれるため、プロファイルの内容を変更した場合はPowerShellウィンドウを再起動してください。
「Microsoft.PowerShell_profile.ps1」
#################################################################################
# PowerShellプロファイル
# (D:\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1)
#
#################################################################################
#################################################################################
# 処理名 | VerificationEnv
# 機能 | PowerShell環境チェック
# | 参考情報:https://zenn.dev/haretokidoki/articles/fac8e50fbe9dcd
#--------------------------------------------------------------------------------
# 戻り値 | MESSAGECODE(enum)
# 引数 | なし
#################################################################################
# エラーコード enum設定
Add-Type -TypeDefinition @"
public enum MESSAGECODE {
Successful = 0,
Abend,
Cancel,
Error_NotCore,
Error_NotSupportedVersion,
Error_NotWindows
}
"@
Function VerificationEnv {
[MESSAGECODE]$return_code = [MESSAGECODE]::Successful
# 環境情報を取得
[System.Collections.Hashtable]$ps_ver = $PSVersionTable
# 環境の判定:Coreではない場合(5.1だと'Desktop'となる)
if ($ps_ver.PSEdition -ne 'Core') {
$return_code = [MESSAGECODE]::Error_NotCore
Write-Host 'Core(6.0以降)の環境ではない' -ForegroundColor Red
}
# 環境の判定:メジャーバージョンが7より小さい場合
elseif ($ps_ver.PSVersion.Major -lt 7) {
$return_code = [MESSAGECODE]::Error_NotSupportedVersion
Write-Host 'Core(6.0以降)の環境だが、7以上 の環境ではない' -ForegroundColor Red
}
# 環境の判定:Windows OSではない場合(PowerShell Coreのみ使用できる自動変数)
elseif (-Not($IsWindows)) {
$return_code = [MESSAGECODE]::Error_NotWindows
Write-Host 'Core(6.0以降)の環境で、かつ 7以上 の環境だが、Windows OS の環境ではない' -ForegroundColor Red
}
else {
Write-Host 'Core(6.0以降)の環境で、かつ 7以上 の環境、Windows OS の環境である'
}
return $return_code
}
#################################################################################
# 処理名 | Get-Datatype
# 機能 | 変数のデータ型を確認
# | 参考情報:https://zenn.dev/haretokidoki/articles/1632e92c37ea98
#--------------------------------------------------------------------------------
# 戻り値 | データ型を表示(項目1:BaseType、項目2:Type)
# 引数 | $variable 調査対象の変数
#################################################################################
Function Get-Datatype {
Param (
[Parameter(Mandatory=$true)]$variable
)
# 文字列配列を宣言
[System.String[]]$rowdata = @(
$variable.GetType().BaseType.FullName, # 変数のベースタイプ
$variable.GetType().FullName # 変数のデータ型
)
# PSCustomObjectで項目名を設定
$types_table = [PSCustomObject]@{
BaseType = $rowdata[0]
DataType = $rowdata[1]
}
# コンソールで表示
$types_table | Format-Table -Property BaseType, DataType -AutoSize -Wrap
}
#################################################################################
# 処理名 | Test-IsAdmin
# 機能 | PowerShellが管理者として実行しているか確認
# | 参考情報:https://zenn.dev/haretokidoki/articles/67788ca9b47b27
#--------------------------------------------------------------------------------
# 戻り値 | Boolean(True: 管理者権限あり, False: 管理者権限なし)
# 引数 | -
#################################################################################
Function Test-IsAdmin {
$win_id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$win_principal = new-object System.Security.Principal.WindowsPrincipal($win_id)
$admin_permission = [System.Security.Principal.WindowsBuiltInRole]::Administrator
return $win_principal.IsInRole($admin_permission)
}
#################################################################################
# 処理名 | GetPsCharcode
# 機能 | PowerShellコンソールの文字コードを取得
# | 参考情報:https://zenn.dev/haretokidoki/articles/67788ca9b47b27
#--------------------------------------------------------------------------------
# 戻り値 | ps_charcode[]
# | - 項目01 文字エンコードを指定できるコマンドレットの既定値
# | - 項目02 PowerShellから外部プログラムに渡す文字エンコードの設定
# | - 項目01 PowerShellのコンソールに出力する文字エンコードの設定
# 引数 | -
#################################################################################
Function GetPsCharcode {
[System.String[]]$ps_charcode = @()
$ps_charcode = @(
# 文字エンコードを指定できるコマンドレットの既定値
($PSDefaultParameterValues['*:Encoding']),
# PowerShellから外部プログラムに渡す文字エンコードの設定
($global:OutputEncoding).WebName,
# PowerShellのコンソールに出力する文字エンコードの設定
([console]::OutputEncoding).WebName
)
return $ps_charcode
}
#################################################################################
# 処理名 | ChangeWindowTitle
# 機能 | PowerShellウィンドウのタイトル変更(文字コードとPowerShellの管理者権限有無を追加)
# | 参考情報:https://zenn.dev/haretokidoki/articles/67788ca9b47b27
#--------------------------------------------------------------------------------
# 戻り値 | -
# 引数 | -
#################################################################################
# PowerShellウィンドウのタイトル変更
Function ChangeWindowTitle {
# 区切り文字の設定
[System.String]$pos1 = '|'
[System.String]$pos2 = ';'
# 現在のタイトルを取得
[System.String]$title = $Host.UI.RawUI.WindowTitle
[System.String]$base_title = $title
# 既にこのFunctionでタイトル変更している場合、一番左にある文字列を抽出
[System.String[]]$title_array = $title.Split($pos1)
if ($title_array.Length -ne 0) {
$base_title = ($title_array[0]).TrimEnd()
}
# 現在の文字コードを取得しタイトルに追加
[System.String[]]$ps_charcode = GetPsCharcode
[System.String]$change_title = $base_title
if (Test-IsAdmin) {
# 管理者として実行している場合
$change_title = $base_title + " $pos1 " +
"DefaultParameter='$($ps_charcode[0])'" + " $pos2 " +
"GlobalEncoding='$($ps_charcode[1])'" + " $pos2 " +
"ConsoleEncoding='$($ps_charcode[2])'" + " $pos2 " +
"#Administrator"
}
else {
# 管理者として実行していない場合
$change_title = $base_title + " $pos1 " +
"DefaultParameter='$($ps_charcode[0])'" + " $pos2 " +
"GlobalEncoding='$($ps_charcode[1])'" + " $pos2 " +
"ConsoleEncoding='$($ps_charcode[2])'" + " $pos2 " +
"#Not_Administrator"
}
$Host.UI.RawUI.WindowTitle = $change_title
# 完了メッセージ
Write-Host 'タイトルに“文字コード”と“管理者権限の有無”の情報を追加しました。' -ForegroundColor Cyan
}
#################################################################################
# 処理名 | SetPsOutputEncoding
# 機能 | PowerShellにおける複数の文字コード設定を一括変更
# | 参考情報:https://zenn.dev/haretokidoki/articles/8946231076f129
#--------------------------------------------------------------------------------
# 戻り値 | -
# 引数 | $charcode(引数を省略した場合は、'reset_encoding'で設定)
# | - 'utf8' : UTF-8に設定
# | - 'sjis' : Shift-JISに設定
# | - 'ascii' : US-ASCIIに設定
# | - 'rm_encoding' : デフォルトパラーメーターを削除
# | - 'reset_encoding': 規定値に戻す
#################################################################################
Function SetPsOutputEncoding {
Param (
[System.String]$charcode = 'reset_encoding'
)
switch ($charcode) {
# 文字エンコードをUTF8に設定する
'utf8' {
$PSDefaultParameterValues['*:Encoding'] = 'utf8'
$global:OutputEncoding = [System.Text.Encoding]::UTF8
[console]::OutputEncoding = [System.Text.Encoding]::UTF8
}
# 文字エンコードをShift JIS(SJIS)に設定する
'sjis' {
# $PSDefaultParameterValues['*:Encoding'] = 'default'について
# この設定はCore以外(5.1以前)の環境でのみShift JISで設定される。
# Core環境のデフォルト値は、UTF-8でありUTF-8で設定されてしまう。
# また、Shift JISのパラメーターも存在しない為、Core環境でShift JISの設定は不可となる。
$PSDefaultParameterValues['*:Encoding'] = 'default'
$global:OutputEncoding = [System.Text.Encoding]::GetEncoding('shift_jis')
[console]::OutputEncoding = [System.Text.Encoding]::GetEncoding('shift_jis')
}
# 文字エンコードをASCIIに設定する
'ascii' {
$PSDefaultParameterValues.Remove('*:Encoding')
$global:OutputEncoding = [System.Text.Encoding]::ASCII
[console]::OutputEncoding = [System.Text.Encoding]::ASCII
}
# デフォルトパラメータの文字エンコード指定を解除する
'rm_encoding' {
$PSDefaultParameterValues.Remove('*:Encoding')
}
# 文字エンコード設定を初期状態に戻す
'reset_encoding' {
$PSDefaultParameterValues.Remove('*:Encoding')
If ($PSVersionTable.PSEdition -eq 'Core') {
# Core の場合
$global:OutputEncoding = [System.Text.Encoding]::UTF8
[console]::OutputEncoding = [System.Text.Encoding]::GetEncoding('shift_jis')
}
else {
# Core 以外の場合(PowerShell 5.1 以前)
$global:OutputEncoding = [System.Text.Encoding]::ASCII
[console]::OutputEncoding = [System.Text.Encoding]::GetEncoding('shift_jis')
}
}
}
# タイトルの表示切替Function呼び出し
ChangeWindowTitle
}
#################################################################################
# 処理名 | Get-PsEncoding
# 機能 | PowerShellでファイルの文字コードを判定
# | 参考情報:https://zenn.dev/haretokidoki/articles/962a7fc6c51b47
#--------------------------------------------------------------------------------
# 戻り値 | -
# 引数 | $targetfile 対象ファイル
#################################################################################
Function Get-PsEncoding {
Param (
[Parameter(Mandatory=$true)][System.String]$targetfile
)
$stream_reader = [System.IO.StreamReader] $targetfile
$profile_encoding = $stream_reader.CurrentEncoding
$stream_reader.Close()
Write-Host "EncodingName: [$($profile_encoding.EncodingName)]"
}
#################################################################################
# 処理名 | Check-BOMStatus
# 機能 | PowerShellでファイルの文字コードにおけるBOMを判定
# | 参考情報:https://zenn.dev/haretokidoki/articles/962a7fc6c51b47
#--------------------------------------------------------------------------------
# 戻り値 | -
# 引数 | $targetfile 対象ファイル
#################################################################################
Function Check-BOMStatus {
Param (
[Parameter(Mandatory=$true)][System.String]$targetfile
)
if (-Not (Test-Path $targetfile)) {
Write-Host 'The target file does not exist.' -ForegroundColor Red
return
}
# BOMのバイトシーケンス
$UTF7_BOM1 = [System.Byte[]](0x2B,0x2F,0x76,0x38)
$UTF7_BOM2 = [System.Byte[]](0x2B,0x2F,0x76,0x39)
$UTF7_BOM3 = [System.Byte[]](0x2B,0x2F,0x76,0x2B)
$UTF7_BOM4 = [System.Byte[]](0x2B,0x2F,0x76,0x2F)
$UTF8_BOM = [System.Byte[]](0xEF,0xBB,0xBF)
$UTF16BE_BOM = [System.Byte[]](0xFE,0xFF)
$UTF16LE_BOM = [System.Byte[]](0xFF,0xFE)
$UTF32BE_BOM = [System.Byte[]](0x00,0x00,0xFE,0xFF)
$UTF32LE_BOM = [System.Byte[]](0xFF,0xFE,0x00,0x00)
# 先頭行をバイトで読み込み先頭から3バイト分のデータを取得
[System.Byte[]]$first_4bytes = (Get-Content -Path $targetfile -Encoding Byte -TotalCount 4)
[System.Byte[]]$first_3bytes = $first_4bytes[0..2]
[System.Byte[]]$first_2bytes = $first_4bytes[0..1]
# 先頭バイトでBOM付きか判定
# UTF-7
if (($null -eq (Compare-Object $first_4bytes $UTF7_BOM1 -SyncWindow 0)) -Or
($null -eq (Compare-Object $first_4bytes $UTF7_BOM2 -SyncWindow 0)) -Or
($null -eq (Compare-Object $first_4bytes $UTF7_BOM3 -SyncWindow 0)) -Or
($null -eq (Compare-Object $first_4bytes $UTF7_BOM4 -SyncWindow 0))) {
Write-Host "[$($targetfile)] is UTF-7 BOM."
}
# UTF-8
elseif ($null -eq (Compare-Object $first_3bytes $UTF8_BOM -SyncWindow 0)) {
Write-Host "[$($targetfile)] is UTF-8 BOM."
}
# UTF-16 BE
elseif ($null -eq (Compare-Object $first_2bytes $UTF16BE_BOM -SyncWindow 0)) {
Write-Host "[$($targetfile)] is UTF-16 BE BOM."
}
# UTF-16 LE
elseif ($null -eq (Compare-Object $first_2bytes $UTF16LE_BOM -SyncWindow 0)) {
Write-Host "[$($targetfile)] is UTF-16 LE BOM."
}
# UTF-32 BE
elseif ($null -eq (Compare-Object $first_4bytes $UTF32BE_BOM -SyncWindow 0)) {
Write-Host "[$($targetfile)] is UTF-32 BE BOM."
}
# UTF-32 LE
elseif ($null -eq (Compare-Object $first_4bytes $UTF32LE_BOM -SyncWindow 0)) {
Write-Host "[$($targetfile)] is UTF-32 LE BOM."
}
else {
Write-Host "[$($targetfile)] is not BOM." -ForegroundColor Red
}
}
#################################################################################
# 処理名 | Get-PyEncoding
# 機能 | Pythonでファイルの文字コードを判定
# | 参考情報:https://zenn.dev/haretokidoki/articles/aea5b45679d966
#--------------------------------------------------------------------------------
# 戻り値 | -
# 引数 | $targetfile 対象ファイル
#################################################################################
Function Get-PyEncoding {
Param (
[Parameter(Mandatory=$true)][System.String]$targetfile
)
# python インストール確認
if (-Not(Get-Command 'python' -ErrorAction SilentlyContinue)) {
Write-Host 'Python is not install.' -ForegroundColor Red
return
}
# 存在チェック
if (-Not(Test-Path $targetfile)) {
Write-Host "[$targetfile] does not exist." -ForegroundColor Red
return
}
# 絶対パスに変換
[System.String]$fullpath_targetfile = (Convert-Path $targetfile)
# データ種類のチェック
if (-Not(Test-Path $fullpath_targetfile -PathType Leaf)) {
Write-Host "[$fullpath_targetfile] is not a file." -ForegroundColor Red
return
}
# Pythonスクリプトのコード
[System.String[]]$py_source =
@"
import subprocess
import sys
# chardet がインストールされていない場合はインストールしてからインポート
try:
import chardet
except ImportError:
subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'chardet', '--user'])
import chardet
# 文字コードを判定するFunction
def determine_encoding(file_path):
with open(file_path, 'rb') as file:
raw_data = file.read()
result = chardet.detect(raw_data)
print(f"Detected encoding for [{file_path}] is {result['encoding']} with {result['confidence']*100}% confidence.")
# コマンドラインの引数を取得
file_path = sys.argv[1]
# 対象ファイルの文字列を判定
determine_encoding(file_path)
"@ -split "`r`n"
# Pythonスクリプトの準備
# Pythonスクリプトを格納するフォルダーがない場合は、新規作成
[System.String]$pyfolder_path = "$PROFILE\..\user-defined-py"
if (-Not(Test-Path $pyfolder_path)) {
New-Item -Path $pyfolder_path -ItemType 'directory' -Force > $null
}
$pyfolder_path = (Convert-Path $pyfolder_path)
# 今回実行するPythonスクリプトがない場合は、新規作成
[System.String]$pyscript_path = "$pyfolder_path\chardet_runner.py"
if (-Not(Test-Path $pyscript_path)) {
$utf8Encoding = New-Object System.Text.UTF8Encoding
[System.IO.File]::WriteAllText($pyscript_path, $py_source, $utf8Encoding)
}
# Pythonスクリプトの実行
try {
python $pyscript_path $fullpath_targetfile
}
catch {
Write-Host 'Python script execution error.'
return
}
}
まとめ
- 下記の2つから自作Functionを読み込み、PowerShellのプロファイルに定義できた!
- ハードコーディングした自作Function
- 専用フォルダー配下にあるps1ファイル内の自作Function
関連記事
Discussion