PowerShellを使用してネットワーク接続のプロファイルを変更する方法

PowerShellを使用してネットワーク接続のプロファイルを変更する方法という問いには、複数プロファイルの旧値を保存し、承認済みマップと差があるInterfaceIndexだけを順番にSet-NetConnectionProfileへ渡すという方法で答えます。InterfaceAliasは変更や重複の可能性があるため、反復処理では取得時のInterfaceIndexと接続名を併記する。管理ポリシーがカテゴリを再適用する環境もある。この記事ではInterfaceIndexを主キーにInterfaceAlias、Name、旧NetworkCategory、期待NetworkCategoryをマップ化するを判断軸にし、実行前の確認、記事固有のコード、合否判定、戻し方を一続きで示します。

seq31の一接続対話変更とは異なり、複数対象を保存マップと差分で反復管理する。完了は「対象Indexごとに期待カテゴリが確認でき、成功・対象消失・ポリシー競合を別々に集計できる」と定義します。対象が取れない場合は「差分0件なら変更不要として正常終了し、すべての接続へ再適用しない」として切り分け、推測で成功扱いにしません。

目次

変更対象をInterfaceIndex一覧で定義

複数プロファイルの旧値を保存し、承認済みマップと差があるInterfaceIndexだけを順番にSet-NetConnectionProfileへ渡す。複数接続のネットワークプロファイル反復変更ではこの進め方により、操作したという事実ではなく、期待する状態へ到達したかでタイトルの問いへ答えられます。seq31の一接続対話変更とは異なり、複数対象を保存マップと差分で反復管理する。

変更対象をInterfaceIndex一覧で定義の合格条件は、対象Indexごとに期待カテゴリが確認でき、成功・対象消失・ポリシー競合を別々に集計できることです。作業時刻、実行ユーザー、端末名を添え、判断に使った値が後から追える形にします。

全プロファイルの旧カテゴリを保存

全プロファイルの旧カテゴリを保存では、複数接続のネットワークプロファイル反復変更の対象を「InterfaceIndexを主キーにInterfaceAlias、Name、旧NetworkCategory、期待NetworkCategoryをマップ化する」という単位で扱います。InterfaceAliasは変更や重複の可能性があるため、反復処理では取得時のInterfaceIndexと接続名を併記する。管理ポリシーがカテゴリを再適用する環境もある。対象が複数なら表示名の部分一致で先頭を採らず、一意になる条件を追加します。

複数接続のネットワークプロファイル反復変更を始める前に、PowerShellの版、コマンドの提供元、必要権限、管理ポリシーの有無を確認します。権限不足と対象なしは意味が異なるため、例外を0件へ置き換えません。

期待カテゴリとの差分だけ抽出

期待カテゴリとの差分だけ抽出は変更前の基準点です。InterfaceIndexを主キーにInterfaceAlias、Name、旧NetworkCategory、期待NetworkCategoryをマップ化するを出力に含め、取得時刻と一緒に保存します。値だけを切り取ると別対象との比較になるため、識別列を省きません。

$desired = [ordered]@{ 'Ethernet'='Private'; 'Wi-Fi'='Public' }
$profilePlan = @(foreach ($alias in $desired.Keys) {
  $rows = @(Get-NetConnectionProfile -InterfaceAlias $alias -ErrorAction Stop)
  if ($rows.Count -ne 1) { throw "$alias のprofileを一意にできません: $($rows.Count)件" }
  $row = $rows[0]
  if ([string]$row.NetworkCategory -eq 'DomainAuthenticated') { throw "$alias はDomainAuthenticatedなので変更しません。" }
  [pscustomobject]@{
    InterfaceIndex=[uint32]$row.InterfaceIndex; InterfaceAlias=[string]$row.InterfaceAlias
    Name=[string]$row.Name; Before=[string]$row.NetworkCategory; Desired=[string]$desired[$alias]
  }
})
$profilePlan | Format-Table -AutoSize

InterfaceAliasは変更や重複の可能性があるため、反復処理では取得時のInterfaceIndexと接続名を併記する。管理ポリシーがカテゴリを再適用する環境もある。出力が多い場合も最初から無理に一件へ絞らず、候補数と除外理由を残してから対象を決めます。

差分表を承認して順次適用

差分表を承認して順次適用では、複数プロファイルの旧値を保存し、承認済みマップと差があるInterfaceIndexだけを順番にSet-NetConnectionProfileへ渡す。複数接続のネットワークプロファイル反復変更の例中にある名前、パス、ID、時刻はサンプルなので、そのまま本番へ貼らず、直前の読み取り結果から承認値を入れます。

if(-not(Get-Variable -Name attemptedLedger -Scope Script -ErrorAction SilentlyContinue)){$script:attemptedLedger=[Collections.Generic.List[object]]::new()}
$selectedAlias='Ethernet' # 1回につき1対象だけ指定
$item=@($profilePlan|Where-Object InterfaceAlias -eq $selectedAlias)
if($item.Count -ne 1){throw 'selected profileをplan内で一意にできません。'}
$item=$item[0]
$current=@(Get-NetConnectionProfile -InterfaceIndex $item.InterfaceIndex -ErrorAction Stop)
if($current.Count -ne 1 -or [uint32]$current[0].InterfaceIndex -ne $item.InterfaceIndex -or [string]$current[0].InterfaceAlias -ne $item.InterfaceAlias -or [string]$current[0].Name -ne $item.Name){throw 'selected profileのexact identityが一致しません。'}
$ledgerRow=@($script:attemptedLedger|Where-Object InterfaceIndex -eq $item.InterfaceIndex)
if($item.Before -eq $item.Desired){[pscustomobject]@{Alias=$item.InterfaceAlias;Result='AlreadyDesiredAtBaseline';Attempted=$false};return}
if([string]$current[0].NetworkCategory -eq $item.Desired){
  if($ledgerRow.Count -ne 1){throw 'ledgerにない外部変更でDesiredになっています。'}
  [pscustomobject]@{Alias=$item.InterfaceAlias;Result='AlreadyAttemptedAndDesired';Attempted=$true};return
}
if([string]$current[0].NetworkCategory -ne $item.Before -or $ledgerRow.Count -ne 0){throw 'selected profileがBeforeでもowned Desiredでもないため停止します。'}
$command="Set-NetConnectionProfile -InterfaceIndex $($item.InterfaceIndex) -NetworkCategory $($item.Desired)"
$token="PREPARE-ONE-PROFILE $($item.InterfaceIndex) $($item.Before)->$($item.Desired)"
if((Read-Host "単発候補を表示する場合は $token を入力") -ne $token){throw '中止しました。'}
$rebind=@(Get-NetConnectionProfile -InterfaceIndex $item.InterfaceIndex -ErrorAction Stop)
if($rebind.Count -ne 1 -or [uint32]$rebind[0].InterfaceIndex -ne $item.InterfaceIndex -or [string]$rebind[0].InterfaceAlias -ne $item.InterfaceAlias -or [string]$rebind[0].Name -ne $item.Name -or [string]$rebind[0].NetworkCategory -ne $item.Before){throw '単発操作直前のidentity/Beforeが一致しません。'}
[pscustomobject]@{Alias=$item.InterfaceAlias;ExecuteAutomatically=$false;ManualCommand=$command}
Read-Host '表示コマンドを手動実行した場合はEnter。未実行でもEnterで結果を確認します'
$after=@(Get-NetConnectionProfile -InterfaceIndex $item.InterfaceIndex -ErrorAction Stop)
if($after.Count -ne 1 -or [uint32]$after[0].InterfaceIndex -ne $item.InterfaceIndex -or [string]$after[0].InterfaceAlias -ne $item.InterfaceAlias -or [string]$after[0].Name -ne $item.Name -or [string]$after[0].NetworkCategory -ne $item.Desired){throw 'selected profileがDesiredにならず、attempt ledgerへ記録しません。'}
$script:attemptedLedger.Add([pscustomobject]@{InterfaceIndex=$item.InterfaceIndex;InterfaceAlias=$item.InterfaceAlias;Name=$item.Name;Before=$item.Before;Desired=$item.Desired;ManualCommand=$command;VerifiedAt=Get-Date})
$script:attemptedLedger|Format-Table -AutoSize

DomainAuthenticatedを上書きしない。途中失敗時に残りの対象へ盲目的に続行せず、結果を保存して判断する。複数接続のネットワークプロファイル反復変更でプレビュー対応コマンドを使える場合はWhatIfを先に実行し、非対応の操作は対象一覧と引数を画面へ出して人が承認してから一度だけ実行します。

各Indexの結果を個別判定

各Indexの結果を個別判定では同じ対象を別経路でもう一度読みます。判定したいのは「コマンドが終了したか」ではなく、対象Indexごとに期待カテゴリが確認でき、成功・対象消失・ポリシー競合を別々に集計できるかどうかです。

if(-not(Get-Variable -Name attemptedLedger -Scope Script -ErrorAction SilentlyContinue)){$script:attemptedLedger=[Collections.Generic.List[object]]::new()}
$ledger=@($script:attemptedLedger)
$wholeTargetRead=@(foreach($item in $profilePlan){
  $row=@(Get-NetConnectionProfile -InterfaceIndex $item.InterfaceIndex -ErrorAction Stop)
  $attempted=@($ledger|Where-Object InterfaceIndex -eq $item.InterfaceIndex).Count -eq 1
  $expectedNow=if($attempted -or $item.Before -eq $item.Desired){$item.Desired}else{$item.Before}
  $exact=$row.Count -eq 1 -and [uint32]$row[0].InterfaceIndex -eq $item.InterfaceIndex -and [string]$row[0].InterfaceAlias -eq $item.InterfaceAlias -and [string]$row[0].Name -eq $item.Name -and [string]$row[0].NetworkCategory -eq $expectedNow
  [pscustomobject]@{InterfaceIndex=$item.InterfaceIndex;Alias=$item.InterfaceAlias;Name=$item.Name;Attempted=$attempted;Expected=$expectedNow;Actual=if($row.Count-eq1){[string]$row[0].NetworkCategory}else{'<missing-or-duplicate>'};Exact=$exact}
})
$wholeTargetRead|Format-Table -AutoSize
$requiredAttempts=@($profilePlan|Where-Object Before -ne Desired).Count
$desiredByIndex=@{};foreach($planned in $profilePlan){$desiredByIndex[[uint32]$planned.InterfaceIndex]=[string]$planned.Desired}
$allApplied=$ledger.Count -eq $requiredAttempts -and @($wholeTargetRead|Where-Object{-not $_.Exact -or $_.Actual -ne $desiredByIndex[[uint32]$_.InterfaceIndex]}).Count -eq 0
if($allApplied){[pscustomobject]@{Completion='WholeTargetDesiredVerified';AttemptedCount=$ledger.Count;Exact=$true};$restoreChoice=Read-Host '手動復元候補を表示する場合は RESTORE-ATTEMPTED、維持する場合はEnter'}else{$restoreChoice='RESTORE-ATTEMPTED';Write-Warning '全対象Desired検証が未完了です。actual attempt ledgerだけを逆順に手動復元します。'}
if($restoreChoice -eq 'RESTORE-ATTEMPTED'){
  $rollbackRows=@($ledger);[array]::Reverse($rollbackRows);$gateErrors=[Collections.Generic.List[string]]::new()
  foreach($attempt in $rollbackRows){
    $current=@(Get-NetConnectionProfile -InterfaceIndex $attempt.InterfaceIndex -ErrorAction Stop)
    if($current.Count -ne 1 -or [uint32]$current[0].InterfaceIndex -ne $attempt.InterfaceIndex -or [string]$current[0].InterfaceAlias -ne $attempt.InterfaceAlias -or [string]$current[0].Name -ne $attempt.Name){$gateErrors.Add("identity:$($attempt.InterfaceAlias)");continue}
    $category=[string]$current[0].NetworkCategory
    if($category -eq $attempt.Before){[pscustomobject]@{Alias=$attempt.InterfaceAlias;Outcome='AlreadyRestored';ManualRollbackCommand=$null};continue}
    if($category -ne $attempt.Desired){$gateErrors.Add("third-state:$($attempt.InterfaceAlias):$category");continue}
    [pscustomobject]@{Alias=$attempt.InterfaceAlias;Outcome='RollbackCandidate';ExecuteAutomatically=$false;ManualRollbackCommand="Set-NetConnectionProfile -InterfaceIndex $($attempt.InterfaceIndex) -NetworkCategory $($attempt.Before)"}
  }
  if($gateErrors.Count){throw "rollback candidate gate failure: $($gateErrors -join '|')"}
  Read-Host '候補を逆順で1行ずつ手動実行した後、Enterで全対象を最終再読します'
  $finalReread=@(foreach($item in $profilePlan){$row=@(Get-NetConnectionProfile -InterfaceIndex $item.InterfaceIndex -ErrorAction SilentlyContinue);$exact=$row.Count -eq 1 -and [uint32]$row[0].InterfaceIndex -eq $item.InterfaceIndex -and [string]$row[0].InterfaceAlias -eq $item.InterfaceAlias -and [string]$row[0].Name -eq $item.Name -and [string]$row[0].NetworkCategory -eq $item.Before;[pscustomobject]@{InterfaceIndex=$item.InterfaceIndex;Alias=$item.InterfaceAlias;Name=$item.Name;Expected=$item.Before;Actual=if($row.Count-eq1){[string]$row[0].NetworkCategory}else{'<missing-or-duplicate>'};Exact=$exact;Outcome=if($exact){'Restored'}else{'RestoreFailed'}}})
  $finalReread|Format-Table -AutoSize
  if(@($finalReread|Where-Object{-not $_.Exact}).Count){throw 'whole-target final rereadにrestore-failedがあります。'}
}

差分0件なら変更不要として正常終了し、すべての接続へ再適用しない。複数接続のネットワークプロファイル反復変更の期待値と実測値が一致しないときは追加変更を重ねず、対象識別、権限、ポリシー、時間差の順で原因を分けます。

GPOで戻される接続を分離

DomainAuthenticatedを上書きしない。途中失敗時に残りの対象へ盲目的に続行せず、結果を保存して判断する。GPOで戻される接続を分離に該当したら、警告を消して継続するのではなく、どの条件で止まったかを記録します。

差分0件なら変更不要として正常終了し、すべての接続へ再適用しない。複数接続のネットワークプロファイル反復変更ではエラー本文、FullyQualifiedErrorId、対象ID、直前に成功した段階を残すと、別担当者が安全な地点から調査できます。

保存マップから一括ではなく逐次復元

旧カテゴリマップをInterfaceIndexとNameの両方で照合し、存在する対象だけを一件ずつ戻す。復旧操作にも同じ識別条件を使い、名前が似た別対象へ戻し処理を適用しません。

  • 複数接続のネットワークプロファイル反復変更の変更前値と取得時刻
  • 復旧対象: InterfaceIndexを主キーにInterfaceAlias、Name、旧NetworkCategory、期待NetworkCategoryをマップ化する
  • 復旧後の判定: 対象Indexごとに期待カテゴリが確認でき、成功・対象消失・ポリシー競合を別々に集計できる
  • 再実行を止める条件: DomainAuthenticatedを上書きしない。途中失敗時に残りの対象へ盲目的に続行せず、結果を保存して判断する

再実行しても差分0件にする

設定管理では期待値、実測値、適用元を保存し、次回実行が差分0件になることを冪等性の基準にする。複数接続のネットワークプロファイル反復変更を繰り返す場合は、正常、対象なし、要承認、失敗を異なる終了状態として記録し、前回値との比較だけで異常を決めません。

再実行しても差分0件にするの識別軸InterfaceIndexを主キーにInterfaceAlias、Name、旧NetworkCategory、期待NetworkCategoryをマップ化する
採用する実測対象Indexごとに期待カテゴリが確認でき、成功・対象消失・ポリシー競合を別々に集計できる
0件時の扱い差分0件なら変更不要として正常終了し、すべての接続へ再適用しない
保留にする兆候DomainAuthenticatedを上書きしない。途中失敗時に残りの対象へ盲目的に続行せず、結果を保存して判断する

複数接続のネットワークプロファイル反復変更の実行記録には、開始前の対象候補、採用した識別値、実行したコード、終了後の実測、除外した候補と理由を同じ作業番号で残します。特に「InterfaceIndexを主キーにInterfaceAlias、Name、旧NetworkCategory、期待NetworkCategoryをマップ化する」を省くと、後日の再確認で別対象の値を比較するおそれがあります。画面コピーだけでなく、日時と端末名を含む構造化した出力も保存します。

PowerShellを使用してネットワーク接続のプロファイルを変更する方法を定期手順へ組み込む場合も、初回は対話的に候補を確認します。正常時は「対象Indexごとに期待カテゴリが確認でき、成功・対象消失・ポリシー競合を別々に集計できる」、判定不能時は「差分0件なら変更不要として正常終了し、すべての接続へ再適用しない」、中止時は「DomainAuthenticatedを上書きしない。途中失敗時に残りの対象へ盲目的に続行せず、結果を保存して判断する」をそれぞれ別の結果として扱います。これにより、0件や例外を都合よく成功へ丸めず、次の担当者が同じ対象と条件で追試できます。

修正後コードの合格条件:desiredの各Indexは現在プロファイル一件へ一致し、DomainAuthenticatedでないことを先に確認します。差分0件なら無変更で終了し、差分があればIndex=New一覧を入力して逐次変更し、各再取得が違えば既に変更したIndexを旧カテゴリへ戻します。

再修正後はGet-NetConnectionProfileのUInt32 InterfaceIndexと同型のDictionaryを使います。複数変更の途中失敗時は逆順に戻し、対象別のrollback結果と旧カテゴリの再取得を必須にします。

安全版 r4b-20260719:複数profileの自動transactionを廃止しました。対象ごとに直前同一性を確認して単発手動変更し、全対象をまとめて読取検証します。不一致時は逆順の手動復元候補を表示し、最後に全対象を再読します。

独立監査追補 r4b-r5-20260719:1回につき明示した1 profileだけをBeforeからDesiredへ進め、成功確認後だけactual attempt ledgerへ記録します。rollbackはledgerを逆順に処理し、Desiredだけに候補を出し、Beforeはskip、第三状態は停止し、全identity/categoryを最終分類します。

公式情報・参考資料

複数接続のネットワークプロファイル反復変更で使うコマンド名、引数、対応環境は次のMicrosoft一次資料で確認しました。記事の確認日は2026年7月17日です。OSやモジュール更新後は、実行端末のGet-Helpと併せて再確認してください。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次