0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【PowerShell 業務自動化レシピ #11】配るスクリプトを「壊れにくく」する(引数化・try/catch・ログ出力)

0
Posted at

株式会社Good Labでエンジニアをしている コータロー です。
日々、Java・SQL・Gitなどの技術情報や、新人エンジニア向けの学習ノウハウ、
AI活用についての情報を発信しています。

Good Labについて気になった方は、コーポレートサイトもぜひご覧ください。
コーポレートサイト


本記事は 「PowerShell 業務自動化レシピ」 シリーズの第11回です。このシリーズは、文法解説ではなく 「1記事=1つの業務課題」を、コピペで動く検証済みスクリプトで解決することを目的とした実務レシピ集です(全12回想定)。SES・受託・社内運用の現場で、いまだに手作業でやっている地味な作業を片っ端から自動化していきます。

第1回 のリネームに始まり、第2回 の古いログ削除、CSV結合・Excel台帳化…と、ここまで10回かけて「手作業を自動化するスクリプト」をたくさん書いてきました。第10回 では、その完成したスクリプトを タスクスケジューラで定期実行 する方法を扱いました。

ここで一度立ち止まります。それらのスクリプト、自分以外のメンバーに渡して大丈夫ですか?別のPC・別のフォルダ構成で動かして壊れませんか?無人のタスクで動いて、もしエラーが出たとき気づけますか?

第11回のテーマは 「配るスクリプトを『壊れにくく』する」。その場限りの使い捨てスクリプトを、人に渡して運用に乗せても壊れない「ちゃんとしたスクリプト」に育てる作法をまとめます。パスやしきい値が直書き、エラーが出ても黙って止まる、何が起きたか記録が残らない——この「使い捨て品質」を「運用品質」に引き上げる回です。

本記事は PowerShell 7(pwsh、クロスプラットフォーム) を基準にしています。Windows標準の Windows PowerShell 5.1 での差異は、各所と最後の章で明記します。

今回は スクリプトの「作り」そのもの がテーマなので、破壊的操作は出てきません。これまでのレシピの仕上げとして、安心して読み進めてください。


Before:使い捨てスクリプトのつらいシーン

シーン1:パスが直書きで、渡した相手の環境で即死

第2回のログ削除スクリプトを「便利だから使って」と後輩に渡したら、開口一番「動きません」。中を見ると $targetDir = "C:\logs" が直書き。後輩の環境ではログは D:\app\logs にあった。結局、渡すたびに 中身を開いて書き換えてもらう ことになり、書き換えミスで全然別のフォルダを処理する事故も起きる。

  • 設定値がコードに埋まっていて、使う人が コードを編集しないと使えない
  • 編集ミス=事故。配るほど事故が増える

シーン2:エラーが出ても「黙って」進む・止まる

「コピー処理が終わったはずなのに、ファイルが揃っていない」。ログを見ても何も残っていない。原因は、コピー元の1フォルダが存在せずエラーになっていたのに、PowerShellの既定動作で「エラーを表示しつつ処理は続行」してしまい、後続が中途半端な状態で完走していたこと。画面には赤いエラーが出ていたが、タスクスケジューラの無人実行だったので 誰も見ていなかった

  • 既定では重大なエラーでも処理が止まらない・気づけない
  • 何時に・何が・なぜ失敗したのか、記録が一切残っていない

これらは全部、スクリプトの「作り」をほんの少し整えるだけで解決します。


After:運用品質のスクリプトに育てる

進め方は ①設定値を引数(param)に追い出す → ②エラーで確実に止めて拾う(try/catch)→ ③実行記録をログファイルに残す → ④前提チェックと冪等性 → ⑤ヘルプと -WhatIf 対応 の順です。最後に、これらを全部盛り込んだ 完成形テンプレート を1本掲載します。コピペして自分のスクリプトの「ガワ」として使ってください。

レシピ1:直書きをやめて引数(param)にする

スクリプトの先頭に param() ブロックを置き、設定値を 外から渡せる引数 にします。第2回のログ削除を題材に、対象フォルダ・日数・拡張子・退避先を引数化します。

param(
    # 必須。対象フォルダ。指定しないと実行時に入力を求められる
    [Parameter(Mandatory = $true)]
    [string]$TargetDir,

    # この日数より古いものを対象にする。既定30、1〜3650の範囲のみ許可
    [ValidateRange(1, 3650)]
    [int]$Days = 30,

    # 対象拡張子。許可リストから選ばせる(タイプミス防止)
    [ValidateSet("*.log", "*.tmp", "*.txt", "*")]
    [string]$Filter = "*.log",

    # 退避先。省略時は対象フォルダの親に _archive を作る
    [string]$ArchiveDir = ""
)

Write-Host "対象フォルダ : $TargetDir"
Write-Host "対象日数     : $Days 日より古いもの"
Write-Host "対象拡張子   : $Filter"

このスクリプトを Cleanup.ps1 として保存すると、こう呼び出せます。

# 必須引数だけ指定(Days・Filter は既定値が使われる)
pwsh -File .\Cleanup.ps1 -TargetDir "D:\app\logs"

# しきい値や拡張子を変えたいときは引数で上書き
pwsh -File .\Cleanup.ps1 -TargetDir "D:\app\logs" -Days 90 -Filter "*.tmp"

-TargetDir を付け忘れると、PowerShellが自動で TargetDir: と入力を促してきます(Mandatory の効果)。-Days 5000 のような範囲外の値や、-Filter "*.csv" のような許可リスト外の値を渡すと、実行前にエラーで弾かれますValidateRange / ValidateSet の効果)。もう中身を書き換えてもらう必要はありません。

レシピ2:エラーで確実に止めて、握りつぶさず拾う(try/catch)

ここが今回の核心です。PowerShellの既定は 「エラーが出ても続行(Continue)」 です。重要な処理は、明示的に「止まるエラー」に変えて try/catch で受け止めます。

# このスクリプト内で発生した「終了させられるエラー」を try/catch で確実に拾う方針
$ErrorActionPreference = "Stop"

try {
    # 重要な処理は -ErrorAction Stop を付けて「止まるエラー」にする
    $items = Get-ChildItem -Path $TargetDir -File -ErrorAction Stop

    if ($items.Count -eq 0) {
        # 異常ではないが伝えたいことは throw せず通知して正常終了
        Write-Host "対象ファイルがありませんでした。"
        return
    }

    Write-Host "処理対象: $($items.Count) 件"
    # ……ここで本処理(コピー・削除・集計など)……
}
catch {
    # catch で握りつぶさない。何が起きたかを必ず出す
    Write-Host "エラーが発生しました: $($_.Exception.Message)"
    # 異常終了であることを呼び出し元(タスクスケジューラ等)に伝える
    exit 1
}
finally {
    # 成否にかかわらず必ず実行したい後始末(一時ファイル削除など)
    Write-Host "処理を終了します。"
}

ポイントは3つです。

  1. -ErrorAction Stop(または $ErrorActionPreference = "Stop")で「止まるエラー」にする。 これをしないと、存在しないフォルダを指定してもエラーを表示しつつ次の行に進んでしまい、catch に入りません。
  2. catch で握りつぶさない。 catch {} と空にするのが最悪です。最低でも $_.Exception.Message を出力(後述のログにも残す)します。
  3. 異常時は exit 1 で「失敗」を返す。 タスクスケジューラは終了コード(0=成功、0以外=失敗)を見ています。exit 1 を返さないと、失敗しても「正常終了」扱いになり気づけません。

レシピ3:実行記録をログファイルに残す(簡易 Write-Log 関数)

「いつ・何が・成功か失敗か・何件処理したか」をファイルに残します。Write-Host画面に出すだけでファイルには残らない ので、運用には不十分です。タイムスタンプ付きでログファイルに追記する小さな関数を用意します。

# ===== ログ出力関数 =====
function Write-Log {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Message,

        # ログレベル。INFO / WARN / ERROR から選ぶ
        [ValidateSet("INFO", "WARN", "ERROR")]
        [string]$Level = "INFO",

        # 出力先ログファイル
        [string]$LogPath = ".\run.log"
    )

    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $line = "[{0}] [{1}] {2}" -f $timestamp, $Level, $Message

    # 画面にも出しつつ、ファイルにも追記(UTF-8で文字化けを防ぐ)
    Write-Host $line
    Add-Content -Path $LogPath -Value $line -Encoding utf8
}

# ===== 使い方 =====
$logPath = ".\cleanup_{0}.log" -f (Get-Date -Format "yyyyMMdd")

Write-Log -Message "処理を開始します(対象: $TargetDir)" -LogPath $logPath
# Write-Log -Message "想定より対象が多いです" -Level WARN -LogPath $logPath
# Write-Log -Message "コピーに失敗しました" -Level ERROR -LogPath $logPath
Write-Log -Message "処理が正常に完了しました(3 件処理)" -LogPath $logPath

実行すると、cleanup_20260630.log にこう追記されます。

[2026-06-30 02:00:01] [INFO] 処理を開始します(対象: D:\app\logs)
[2026-06-30 02:00:02] [INFO] 処理が正常に完了しました(3 件処理)

Add-Content追記 なので、毎回の実行が下に積み上がります。ファイル名に日付(yyyyMMdd)を入れておくと、日ごとにログが分かれて見やすく、肥大化も防げます(その古いログ掃除こそ第2回のレシピの出番です)。

文字コードの注意:Add-Content -Encoding utf8必ず付けてください。付けないと、PowerShell 5.1 では既定がShift_JIS系になり、日本語を含むログが他ツールで開いたとき文字化けします。詳しくは最後の差異表で触れます。

レシピ4:前提チェックと冪等性で「何度実行しても安全」に

無人で繰り返し動くスクリプトは、入力が無い・フォルダが無い・既に処理済み といった状況でも穏当に振る舞う必要があります。処理本体に入る前に「前提」を確認し、満たさないなら早期に切り上げます。

# 前提1:入力フォルダが存在するか(無ければ ERROR ログを残して異常終了)
if (-not (Test-Path -LiteralPath $TargetDir)) {
    Write-Log -Message "対象フォルダが存在しません: $TargetDir" -Level ERROR -LogPath $logPath
    exit 1
}

# 前提2:対象が0件なら「異常ではない」ので正常終了(早期 return)
$items = @(Get-ChildItem -Path $TargetDir -File -Filter $Filter -ErrorAction Stop)
if ($items.Count -eq 0) {
    Write-Log -Message "対象ファイルは0件でした。処理をスキップします。" -LogPath $logPath
    return
}

# 前提3:出力先フォルダを冪等に用意(既にあれば作らない・あってもエラーにしない)
$outDir = Join-Path $TargetDir "_processed"
if (-not (Test-Path -LiteralPath $outDir)) {
    New-Item -ItemType Directory -Path $outDir | Out-Null
}

冪等(べきとう)性 とは「同じ操作を何回実行しても、結果が同じ(壊れない)」という性質です。たとえば出力先フォルダの作成は、Test-Path で存在を確認してから作ることで、2回目以降に「既に存在します」エラーで止まらなくなります。定期実行されるスクリプトでは、この「何度動かしても大丈夫」が信頼性の土台になります。

  • 「0件」と「エラー」を区別する。 対象が無いのは多くの場合 正常 です。exit 1(異常)ではなく return(正常終了)で抜けます。
  • @(...) で配列化 しておくと、0件・1件でも .Count が安定して取れます(5.1対策。第2回でも触れた定番)。

レシピ5:ヘルプ(-?)と -WhatIf に対応する

人に配るなら「使い方」をスクリプト自身に持たせます。先頭に コメントベースヘルプ を書くと、Get-Help-? で説明が出ます。

<#
.SYNOPSIS
    指定フォルダ内の、N日より古いファイルをアーカイブ退避する運用スクリプト。

.DESCRIPTION
    対象フォルダから -Filter で絞ったファイルのうち、-Days 日より古いものを
    退避先フォルダに移動します。実行結果は日付別ログファイルに記録します。

.PARAMETER TargetDir
    処理対象のフォルダパス(必須)。

.PARAMETER Days
    この日数より古いファイルを対象にします(既定: 30)。

.EXAMPLE
    pwsh -File .\Cleanup.ps1 -TargetDir "D:\app\logs"
    D:\app\logs の30日より古いログを退避します。

.EXAMPLE
    pwsh -File .\Cleanup.ps1 -TargetDir "D:\app\logs" -Days 90 -WhatIf
    90日より古いログについて、実際には移動せず「何が起きるか」だけ表示します。
#>

これを書いておくと、利用者は中身を読まなくても次で使い方を確認できます。

# どちらでもヘルプが表示される
Get-Help .\Cleanup.ps1 -Full
pwsh -File .\Cleanup.ps1 -?

さらに、自作の処理にも第1回から使ってきた -WhatIf を効かせる ことができます。param() の直前に [CmdletBinding(SupportsShouldProcess = $true)] を付け、破壊的操作を $PSCmdlet.ShouldProcess(...) で囲みます。

[CmdletBinding(SupportsShouldProcess = $true)]
param(
    [Parameter(Mandatory = $true)]
    [string]$TargetDir
)

foreach ($file in $items) {
    # -WhatIf 付きで呼ぶと、ここは実行されず「何が起きるか」だけ表示される
    if ($PSCmdlet.ShouldProcess($file.FullName, "アーカイブへ移動")) {
        Move-Item -LiteralPath $file.FullName -Destination $outDir
    }
}

これで、自作スクリプトでも Move-Item などの組み込みコマンドと同じく -WhatIf でドライランできる ようになります。配布物としての完成度がぐっと上がります。

レシピ6:全部入りの完成形テンプレート

ここまでの要素を1本にまとめた「ガワ」です。あなたのスクリプトの本処理を # ===== 本処理 ===== の中に書くだけで、引数化・エラー処理・ログ・前提チェック・ヘルプ・WhatIf を備えた運用品質のスクリプトになります。

<#
.SYNOPSIS
    運用スクリプトの汎用テンプレート(引数化・エラー処理・ログ出力つき)。
.DESCRIPTION
    本処理部分(# ===== 本処理 =====)を差し替えて使う土台。
.PARAMETER TargetDir
    処理対象のフォルダパス(必須)。
.PARAMETER LogDir
    ログの出力先フォルダ(既定: スクリプトと同じ場所)。
.EXAMPLE
    pwsh -File .\Template.ps1 -TargetDir "D:\app\data"
#>
[CmdletBinding(SupportsShouldProcess = $true)]
param(
    [Parameter(Mandatory = $true)]
    [string]$TargetDir,

    [string]$LogDir = $PSScriptRoot
)

# このスクリプト内のエラーは原則「止まるエラー」にして catch で拾う
$ErrorActionPreference = "Stop"

# ===== ログ関数 =====
function Write-Log {
    param(
        [Parameter(Mandatory = $true)][string]$Message,
        [ValidateSet("INFO", "WARN", "ERROR")][string]$Level = "INFO"
    )
    $ts   = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $line = "[{0}] [{1}] {2}" -f $ts, $Level, $Message
    Write-Host $line
    Add-Content -Path $script:LogPath -Value $line -Encoding utf8
}

# ログファイルのパスを決める(スクリプトと同じ場所・日付別)
$script:LogPath = Join-Path $LogDir ("run_{0}.log" -f (Get-Date -Format "yyyyMMdd"))

try {
    Write-Log -Message "==== 処理開始(対象: $TargetDir)===="

    # 前提チェック:入力フォルダの存在
    if (-not (Test-Path -LiteralPath $TargetDir)) {
        throw "対象フォルダが存在しません: $TargetDir"
    }

    # ===== 本処理(ここを自分の処理に差し替える)=====
    $items = @(Get-ChildItem -Path $TargetDir -File -ErrorAction Stop)
    if ($items.Count -eq 0) {
        Write-Log -Message "対象は0件でした。処理をスキップします。" -Level WARN
        return
    }

    Write-Log -Message "$($items.Count) 件を処理します。"
    # foreach ($f in $items) { ... 実際の処理 ... }
    # ===== 本処理ここまで =====

    Write-Log -Message "==== 正常終了($($items.Count) 件処理)===="
}
catch {
    # 例外メッセージと、どの行で起きたか(ScriptLineNumber)を記録
    $line = $_.InvocationInfo.ScriptLineNumber
    Write-Log -Message "異常終了: $($_.Exception.Message)$line 行目付近)" -Level ERROR
    exit 1   # 失敗をタスクスケジューラに伝える
}
finally {
    Write-Log -Message "==== 後処理を実行しました ===="
}

正常時のログ出力イメージ:

[2026-06-30 02:00:00] [INFO] ==== 処理開始(対象: D:\app\data)====
[2026-06-30 02:00:01] [INFO] 3 件を処理します。
[2026-06-30 02:00:02] [INFO] ==== 正常終了(3 件処理)====
[2026-06-30 02:00:02] [INFO] ==== 後処理を実行しました ====

異常時(フォルダが無い場合)のログ出力イメージ:

[2026-06-30 02:05:00] [INFO] ==== 処理開始(対象: D:\app\nothing)====
[2026-06-30 02:05:00] [ERROR] 異常終了: 対象フォルダが存在しません: D:\app\nothing(30 行目付近)
[2026-06-30 02:05:00] [INFO] ==== 後処理を実行しました ====

throw で投げた例外も、catch がきっちり拾って ERROR ログに残し、finally の後始末まで通った上で exit 1 で終わっている点に注目してください。これが「壊れにくいスクリプト」の最低ライン形です。


コードの要点解説(なぜこの書き方か)

文法そのものではなく、配って運用に乗せても事故らないための選択 を中心に解説します。

1. なぜ既定の「続行」が危険なのか

PowerShellの $ErrorActionPreference の既定値は Continue(エラーを表示しつつ処理続行)です。対話操作なら画面の赤字に気づけますが、無人のタスクでは誰も見ていません。「コピー元が無い」程度のエラーを表示だけして後続に進み、中途半端な状態で「正常終了」してしまう——これが一番怖いパターンです。だからこそ、重要処理は -ErrorAction Stop(または冒頭の $ErrorActionPreference = "Stop")で 明示的に止めtry/catch で拾います。

2. Write-Host とログの違い

Write-Host画面(ホスト)に書くだけ で、ファイルにもパイプラインにも残りません。便利ですが、無人実行では出力先が無く消えてしまいます。後から「いつ何が起きたか」を追うには、Add-Content でファイルに残す必要があります。本記事の Write-Log画面表示(Write-Host)とファイル追記(Add-Content)の両方 をやっているので、対話実行でも無人実行でも記録が残ります。

3. exit 1 と終了コードの意味

タスクスケジューラやCI、別スクリプトからの呼び出しは、終了コード$LASTEXITCODE で参照できる値)で成否を判断します。慣例として 0=成功、0以外=失敗 です。catchexit 1 を返さないと、内部でエラーが起きても呼び出し元には「成功」と伝わってしまい、失敗が握りつぶされます。「異常時は必ず exit 1」をルールにしてください。

4. $PSScriptRoot 基準でパスを組む(相対パスの罠)

ログ出力先に ".\run.log" のような相対パスを使うと、「実行時のカレントディレクトリ」基準 になります。タスクスケジューラから起動すると、カレントが C:\Windows\System32 などになり、意図しない場所にログが出る(あるいは権限エラーになる)事故が頻発します。$PSScriptRootスクリプトファイル自身が置かれているフォルダ)を基準にすれば、どこから起動されても同じ場所に出力できます。テンプレートで $LogDir = $PSScriptRoot を既定にしているのはこのためです。

5. [ValidateSet] / [ValidateRange] で「変な値」を入口で弾く

引数の検証属性は、本処理に入る前に 不正な入力をエラーにします。-Days -5-Filter "*.exe" のような値が、処理の途中まで進んでから変な挙動をする——を未然に防ぎます。配る相手のタイプミスや勘違いを、コード本体に到達させないための「門番」です。

6. throwWrite-Log -Level ERROR の使い分け

throw は「ここから先は続けられない」という 処理の中断 を意味し、catch まで一気に飛びます。一方 Write-Log -Level ERROR は「記録は残すが、処理自体は止めない/別途 exit で制御する」場合に使います。テンプレートでは、前提チェックの致命的エラーは throwcatch に集約し、ログ記録は catch 内の Write-Log に一本化することで、エラー時の記録漏れを防いでいます


応用・注意点

① catch で「握りつぶし」は最悪。最低でもログに残す

一番やってはいけないのが catch { }(空)や catch { }で何もしないことです。エラーが闇に消え、後から原因究明が不可能になります。握りつぶすくらいなら try/catch を書かないほうがまし(少なくとも画面に赤字が出る)です。catch を書くなら、必ず $_.Exception.Message をログに残してください。

② 特定のエラーだけ握って、続行したいとき

「1件失敗しても、残りは処理を続けたい」こともあります。その場合は、ループの内側に try/catch を置き、1件分のエラーをログに残して次へ進めます。

foreach ($file in $items) {
    try {
        Move-Item -LiteralPath $file.FullName -Destination $outDir -ErrorAction Stop
        Write-Log -Message "移動成功: $($file.Name)"
    }
    catch {
        # この1件だけ失敗を記録して、ループは継続
        Write-Log -Message "移動失敗(スキップ): $($file.Name) - $($_.Exception.Message)" -Level WARN
        continue
    }
}

外側で全体を止めるか、内側で1件ずつ拾って続けるか。「止めるべき失敗」と「スキップしてよい失敗」を意識して使い分けるのが運用設計の肝です。

③ ログファイル自体が肥大化・文字化けする

ログを追記し続けると、いつかファイルが巨大になります。日付別ファイル名(run_yyyyMMdd.log)にして、古いログは第2回のレシピで自動削除 するのが定石です。また、Add-Content-Encoding utf8 を付け忘れると、5.1環境で日本語が文字化けします。ログは後で人が読むものなので、文字コードは最初から utf8 で固定しておきましょう。

④ 実行ポリシーで「そもそも動かない」ことがある

配った先で .ps1 をダブルクリックや右クリック実行しようとすると、実行ポリシーに阻まれて動かないことがあります。タスクスケジューラ等から呼ぶ場合は、第2回・第10回でも使った -ExecutionPolicy Bypass を付けるのが実務的です(実行ポリシーの罠そのものは、次回・最終回で詳しく扱います)。

pwsh -NoProfile -ExecutionPolicy Bypass -File C:\scripts\Template.ps1 -TargetDir "D:\app\data"

⑤ Windows PowerShell 5.1 との差異

本記事の作法は、コアな部分は 5.1 でもそのまま通用 します。ただし以下に注意してください。

項目 PowerShell 7(pwsh) Windows PowerShell 5.1
Add-Content -Encoding utf8 UTF-8(BOMなし)で出力 UTF-8 (BOM付き) で出力される。他ツールが先頭に謎の文字を表示することがある
既定の文字コード UTF-8 レガシー(Shift_JIS/ANSI系)。-Encoding 未指定だと日本語ログが化けやすい
$PSScriptRoot 利用可 利用可(PowerShell 3.0以降)
[CmdletBinding] / SupportsShouldProcess 利用可 利用可
0件結果の .Count 安定して取れる $null だと取れないことがある → @(...) で配列化推奨
タスクの実行ファイル pwsh.exe powershell.exe

5.1で -Encoding utf8 を使うと BOM付きUTF-8 になります。多くの環境では問題ありませんが、BOMを嫌うツールに渡すなら、5.1では Out-File -Encoding utf8NoBOM(※5.1には utf8NoBOM が無いため [System.IO.File]::AppendAllText を使う等)の検討が必要です。込み入った話なので、まずは 「PowerShell 7なら BOMなしUTF-8 で素直」 と覚えておけば十分です。


まとめ

  • 設定値は直書きをやめて param()Mandatory / ValidateSet / ValidateRange で外出し
  • PowerShellの既定は 「エラーでも続行」。重要処理は -ErrorAction Stoptry/catch確実に止めて拾う
  • catch握りつぶさない$_.Exception.Message をログに残し、異常時は exit 1
  • Write-Host は画面のみ。タイムスタンプ付きログ(Add-Content -Encoding utf8) で記録を残す
  • 相対パスは危険。$PSScriptRoot 基準でパスを組む
  • 前提チェック・冪等性・コメントベースヘルプ・-WhatIf 対応で「配れる」品質へ

第1回から積み上げてきた「使い捨ての自動化」を、これで 人に渡せる・無人で回せる運用品質 に引き上げられます。今回の完成形テンプレートを「ガワ」として、過去のレシピを包み直してみてください。

次回はいよいよ 最終回・第12回「現場でハマる罠10選(文字コード・改行・$null比較・実行ポリシー)」。本シリーズで何度も顔を出した「文字化け」「$null の比較」「実行ポリシー」など、PowerShell初心者が必ず一度は踏む地雷を、まとめて10個解説します。お楽しみに。


参考


@kotaro_ai_lab
AI活用や開発効率化について発信しています。フォローお気軽にどうぞ!

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?