ラベル Powershell の投稿を表示しています。 すべての投稿を表示
ラベル Powershell の投稿を表示しています。 すべての投稿を表示

2026年2月12日木曜日

Windows のルーティング情報を可視化する Powershell

Windows のルーティング情報を可視化する Powershell

概要

タイトル通り

環境

  • Windows 11

スクリプト

# Visualize-Routes.ps1 (vis.jsを使用したHTMLベースの可視化)

param (
    [string]$OutputPath = "$($PSScriptRoot)\network_routes.html",
    [switch]$IncludeDefaultRoutes = $false,
    [string[]]$ExcludeNextHops = @()
)

function Visualize-NetRouteGraph {
    [CmdletBinding()]
    param (
        [string]$OutputPath = "$($PSScriptRoot)\network_routes.html",
        [switch]$IncludeDefaultRoutes = $false,
        [string[]]$ExcludeNextHops = @()
    )

    # ルーティング情報を取得
    $routes = Get-NetRoute
    
    # デフォルトルートを除外する場合
    if (-not $IncludeDefaultRoutes) {
        $routes = $routes | Where-Object { $_.NextHop -ne "::" -and $_.NextHop -ne "0.0.0.0" }
    }
    
    # 指定されたNextHopを除外する場合
    if ($ExcludeNextHops.Count -gt 0) {
        foreach ($excludeHop in $ExcludeNextHops) {
            $routes = $routes | Where-Object { $_.NextHop -ne $excludeHop }
        }
    }

    if (-not $routes) {
        Write-Warning "ルーティング情報が見つかりませんでした。"
        return
    }

    # ノードとエッジの定義
    $nodes = @{}
    $edges = @()
    $nodeId = 0
    $nodeMap = @{}
    $edgeMap = @{}  # エッジの重複を管理

    foreach ($route in $routes) {
        $destination = $route.DestinationPrefix
        $nextHop = $route.NextHop
        $ifIndex = $route.IfIndex
        $interface = $null
        
        # ネットワークアダプタ名を取得(エラーハンドリング付き)
        try {
            $interface = (Get-NetAdapter -IfIndex $ifIndex -ErrorAction Stop).Name
        }
        catch {
            $interface = $null
        }

        # ノードの作成(重複なし)
        if (-not $nodeMap.ContainsKey($destination)) {
            $nodeMap[$destination] = @{
                id    = $nodeId
                label = $destination
                title = "Destination: $destination"
                color = "lightblue"
                shape = "box"
            }
            $nodeId++
        }

        if (-not $nodeMap.ContainsKey($nextHop)) {
            $nodeMap[$nextHop] = @{
                id    = $nodeId
                label = $nextHop
                title = "NextHop: $nextHop"
                color = "lightgreen"
                shape = "ellipse"
            }
            $nodeId++
        }

        # エッジのキーを作成(重複チェック用)
        # NextHop → Destination の向きにすることで、トラフィックフローを表現
        $edgeKey = "$($nodeMap[$nextHop].id)->$($nodeMap[$destination].id)"
        
        # エッジラベルの作成
        $edgeInfo = "Metric: $($route.RouteMetric)"
        if ($interface) {
            $edgeInfo += " (via $interface)"
        }
        
        # 既存のエッジがあれば統合、なければ新規作成
        if ($edgeMap.ContainsKey($edgeKey)) {
            # 既存のエッジにラベルを追加
            $edgeMap[$edgeKey].labels += $edgeInfo
        }
        else {
            # 新規エッジを作成
            $edgeMap[$edgeKey] = @{
                from   = $nodeMap[$nextHop].id
                to     = $nodeMap[$destination].id
                labels = @($edgeInfo)
            }
        }
    }
    
    # エッジマップからエッジ配列を作成(ラベルを結合)
    foreach ($edgeKey in $edgeMap.Keys) {
        $edge = $edgeMap[$edgeKey]
        $edges += @{
            from  = $edge.from
            to    = $edge.to
            label = $edge.labels -join "`n"
        }
    }

    # JSON形式でノードとエッジを作成
    $nodesJson = $nodeMap.Values | ConvertTo-Json
    $edgesJson = $edges | ConvertTo-Json

    # HTMLテンプレートを生成
    $htmlContent = @"
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ネットワークルーティンググラフ</title>
    <script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        html, body {
            width: 100%;
            height: 100%;
            font-family: Arial, sans-serif;
        }
        #network {
            width: 100%;
            height: 100%;
            border: 1px solid lightgray;
        }
        .controls {
            position: absolute;
            top: 10px;
            left: 10px;
            background: white;
            padding: 10px;
            border: 1px solid #ccc;
            border-radius: 5px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.2);
            z-index: 100;
        }
        button {
            padding: 5px 10px;
            margin: 5px 2px;
            cursor: pointer;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
        }
        button:hover {
            background-color: #45a049;
        }
    </style>
</head>
<body>
    <div class="controls">
        <button onclick="resetView()">リセット</button>
        <button onclick="fitToScreen()">画面に合わせる</button>
    </div>
    <div id="network"></div>

    <script type="text/javascript">
        var nodes = new vis.DataSet($nodesJson);
        var edges = new vis.DataSet($edgesJson);

        var container = document.getElementById('network');
        var data = {
            nodes: nodes,
            edges: edges
        };

        var options = {
            physics: {
                enabled: true,
                stabilization: {
                    iterations: 200
                },
                barnesHut: {
                    gravitationalConstant: -26000,
                    centralGravity: 0.3,
                    springLength: 300,
                    springConstant: 0.04,
                    damping: 0.3
                }
            },
            nodes: {
                font: {
                    size: 14,
                    color: 'black'
                },
                borderWidth: 2,
                shadow: true
            },
            edges: {
                arrows: 'to',
                font: {
                    size: 12,
                    align: 'middle'
                },
                shadow: true,
                smooth: {
                    type: 'continuous'
                }
            },
            interaction: {
                navigationButtons: true,
                keyboard: true,
                zoomView: true,
                dragView: true
            }
        };

        var network = new vis.Network(container, data, options);

        function resetView() {
            network.fit();
        }

        function fitToScreen() {
            network.fit({
                animation: {
                    duration: 1000,
                    easingFunction: 'easeInOutQuad'
                }
            });
        }

        window.addEventListener('resize', function() {
            network.redraw();
        });

        network.fit();
    </script>
</body>
</html>
"@

    # HTMLファイルを保存
    $htmlContent | Set-Content $OutputPath -Encoding UTF8

    Write-Host "ネットワークルーティンググラフをHTMLで生成しました: $OutputPath"
    Write-Host "ブラウザで表示しています..."

    # ブラウザで開く
    Invoke-Item $OutputPath
}

# 関数を実行(スクリプトの引数を渡す)
$params = @{
    OutputPath = $OutputPath
}
if ($IncludeDefaultRoutes) {
    $params['IncludeDefaultRoutes'] = $IncludeDefaultRoutes
}
if ($ExcludeNextHops.Count -gt 0) {
    $params['ExcludeNextHops'] = $ExcludeNextHops
}
Visualize-NetRouteGraph @params

最後に

作成された HTML をブラウザ開けば OK です

2026年2月10日火曜日

Outlook の受信トレイにあるメールを検索する Powershell

Outlook の受信トレイにあるメールを検索する Powershell

概要

タイトル通り

環境

  • Windows 11

スクリプト

param(
    [string]$Keyword = "test",
    [switch]$SearchBody = $false
)

try {
    Write-Host "Connecting to Outlook..."

    $ErrorActionPreference = "Stop"

    $Outlook = New-Object -ComObject Outlook.Application
    $Namespace = $Outlook.GetNamespace("MAPI")
    $Namespace.Logon()

    $Inbox = $Namespace.GetDefaultFolder(6)

    Write-Host "Searching in $($Inbox.Name)"
    Write-Host "Keyword: $Keyword"
    Write-Host "Search Body: $SearchBody"

    $Items = $Inbox.Items
    Write-Host "Total items: $($Items.Count)"

    $FoundItems = @()
    $count = 0
    foreach ($Item in $Items) {
        $count++
        if ($count % 100 -eq 0) {
            Write-Host "Processing item $count..."
        }
        if ($SearchBody) {
            if ($Item.Subject -match $Keyword -or $Item.Body -match $Keyword) {
                $FoundItems += $Item
            }
        }
        else {
            if ($Item.Subject -match $Keyword) {
                $FoundItems += $Item
            }
        }
    }

    Write-Host "Found: $($FoundItems.Count) emails"

    if ($FoundItems.Count -gt 0) {
        foreach ($MailItem in $FoundItems) {
            Write-Host "-----"
            Write-Host "Subject: $($MailItem.Subject)"
            Write-Host "Sender: $($MailItem.SenderName)"
            Write-Host "Received: $($MailItem.ReceivedTime)"
        }
    }
    else {
        Write-Host "No emails found."
    }

    if ($Inbox) { [System.Runtime.InteropServices.Marshal]::ReleaseComObject($Inbox) | Out-Null }
    if ($Namespace) { [System.Runtime.InteropServices.Marshal]::ReleaseComObject($Namespace) | Out-Null }
    if ($Outlook) { [System.Runtime.InteropServices.Marshal]::ReleaseComObject($Outlook) | Out-Null }

    Write-Host "Done."
}
catch {
    Write-Host "Error: $($_.Exception.Message)"
}

最後に

日本語で検索すると文字コードエラーになる場合があるのでその場合は検索キーワードを引数で受け取るようにしましょう
メールの件数が多いとかなり時間がかかるのでタイトルだけで検索するなどの工夫をしましょう
進捗がわかりづらい場合などがあるので 100件ずつ分割して検索してもいいと思います

2026年2月8日日曜日

VSCode で Powershell をフォーマットする方法

VSCode で Powershell をフォーマットする方法

概要

VSCode を使うのが一番簡単のようです

環境

  • Windows11
  • VSCode 1.108.2

フォーマット

  • ps1 ファイルを開く
  • 右クリックから「Format Document」

リント

lint は CLI でできます

Invoke-ScriptAnalyzer -Path .\test.ps1

最後に

全部 CLI でやりたい

参考サイト

2026年1月29日木曜日

Windows11 のプロキシ設定のセットアップスクリプトを Powershell で設定する

Windows11 のプロキシ設定のセットアップスクリプトを Powershell で設定する

概要

タイトルの通りです

環境

  • Windows11

Powershell スクリプト

# Windows proxy setup script configuration tool
# Usage: .\change_proxy.ps1 -ScriptURL "http://xxx.xxx.xxx.xxx/proxy.pac"
#        .\change_proxy.ps1 -Reset

param(
    [string]$ScriptURL = "http://xxx.xxx.xxx.xxx/proxy.pac",
    [switch]$Reset = $false
)

# Check admin privileges
function Test-IsAdmin {
    $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
    return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

# Elevate to admin if needed
if (-not (Test-IsAdmin)) {
    Write-Host "Admin privileges required. Elevating..." -ForegroundColor Yellow
    $scriptPath = $MyInvocation.MyCommand.Path
    $arguments = "-NoProfile -ExecutionPolicy Bypass -File `"$scriptPath`""
    if ($ScriptURL -ne "http://xxx.xxx.xxx.xxx/proxy.pac") {
        $arguments += " -ScriptURL `"$ScriptURL`""
    }
    if ($Reset) {
        $arguments += " -Reset"
    }
    Start-Process PowerShell -ArgumentList $arguments -Verb RunAs -Wait
    exit 0
}

if ($Reset) {
    # Reset proxy settings
    Write-Host "Resetting proxy settings..."
    netsh winhttp reset proxy

    # Reset registry settings
    $regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
    if (Test-Path $regPath) {
        Set-ItemProperty -Path $regPath -Name ProxyEnable -Value 0 -ErrorAction SilentlyContinue
        Set-ItemProperty -Path $regPath -Name AutoConfigURL -Value "" -ErrorAction SilentlyContinue
        Set-ItemProperty -Path $regPath -Name AutoDetect -Value 0 -ErrorAction SilentlyContinue
        Set-ItemProperty -Path $regPath -Name ProxyServer -Value "" -ErrorAction SilentlyContinue
        Write-Host "Proxy settings reset." -ForegroundColor Green
    }
} else {
    # Configure setup script
    Write-Host "Configuring setup script: $ScriptURL"

    $regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
    if (-not (Test-Path $regPath)) {
        New-Item -Path $regPath -Force | Out-Null
    }

    # Disable direct proxy
    Set-ItemProperty -Path $regPath -Name ProxyEnable -Value 0 -ErrorAction SilentlyContinue
    # Set auto-config script
    Set-ItemProperty -Path $regPath -Name AutoConfigURL -Value $ScriptURL -ErrorAction SilentlyContinue
    # Disable auto-detect
    Set-ItemProperty -Path $regPath -Name AutoDetect -Value 0 -ErrorAction SilentlyContinue

    Write-Host "Setup script configured." -ForegroundColor Green
}

# Display current settings
Write-Host "`nCurrent proxy settings:" -ForegroundColor Cyan
$regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
if (Test-Path $regPath) {
    $proxyEnable = (Get-ItemProperty -Path $regPath -Name ProxyEnable -ErrorAction SilentlyContinue).ProxyEnable
    $autoConfigURL = (Get-ItemProperty -Path $regPath -Name AutoConfigURL -ErrorAction SilentlyContinue).AutoConfigURL
    $autoDetect = (Get-ItemProperty -Path $regPath -Name AutoDetect -ErrorAction SilentlyContinue).AutoDetect
    $proxyServer = (Get-ItemProperty -Path $regPath -Name ProxyServer -ErrorAction SilentlyContinue).ProxyServer

    Write-Host "  ProxyEnable: $proxyEnable"
    Write-Host "  AutoConfigURL: $autoConfigURL"
    Write-Host "  AutoDetect: $autoDetect"
    Write-Host "  ProxyServer: $proxyServer"
}
Write-Host ""
netsh winhttp show proxy

最後に

当然ですが管理者権限が必要になります

2026年1月24日土曜日

RDP で毎回認証を求められるがそれを回避して認証情報なしで自動で接続する方法

RDP で毎回認証を求められるがそれを回避して認証情報なしで自動で接続する方法

概要

ダウンロードした RDP ファイルをコピーして書き換えて実行します 前回の続きです

環境

  • Windows11

monitory_rdp_file.ps1

param(
    [Parameter(Mandatory=$false)]
    [string]$RDPServer = "your.rdp.server.or.ip",
    
    [Parameter(Mandatory=$false)]
    [string]$RDPUsername = "domain\username",
    
    [Parameter(Mandatory=$false)]
    [string]$RDPPassword = "xxxx",
    
    [Parameter(Mandatory=$false)]
    [switch]$TestMode = $false
)

# Basic file logging to help diagnose scheduled task behavior
$logDir = Join-Path $env:LOCALAPPDATA "RDPFileMonitor"
if (-not (Test-Path $logDir)) {
    New-Item -Path $logDir -ItemType Directory -Force | Out-Null
}
$logPath = Join-Path $logDir "monitor.log"

# Emit a simple startup marker
("Started: " + (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')) | Out-File -FilePath (Join-Path $logDir 'started.txt') -Append -Encoding utf8

try {
    Start-Transcript -Path $logPath -Append -ErrorAction SilentlyContinue | Out-Null
} catch {}

# Get user profile path - handle both system and user context execution
$userProfile = [Environment]::GetFolderPath("UserProfile")
if (-not (Test-Path $userProfile)) {
    $userProfile = "C:\Users\username"
}
$downloadFolder = Join-Path $userProfile "Downloads"
$targetRDPFileName = "rdgateway101_vdgate_nifcloud_net.rdp"
$processedFiles = @()

Write-Host "Starting RDP file monitoring (polling method)"
Write-Host "Executed by: $env:USERNAME from host: $env:COMPUTERNAME"
Write-Host "User Profile: $userProfile"
Write-Host "Log: $logPath"
Write-Host "Target folder: $downloadFolder"
Write-Host "Target file name: $targetRDPFileName"

if ($TestMode) {
    Write-Host "Test Mode: Running one iteration only"
} else {
    Write-Host "Checking every 2 seconds..."
}

$iterationCount = 0
$maxIterations = if ($TestMode) { 1 } else { [int]::MaxValue }

while ($iterationCount -lt $maxIterations) {
    $iterationCount++
    Write-Host "Iteration $iterationCount at $(Get-Date -Format 'HH:mm:ss')" -ForegroundColor Gray
    
    try {
        if (Test-Path $downloadFolder) {
            # Clean up processed files list - remove entries for files that no longer exist
            $processedFiles = @($processedFiles | Where-Object { Test-Path $_ })
            
            $files = Get-ChildItem -Path $downloadFolder -Filter "*.rdp" -File
            
            foreach ($file in $files) {
                if ($file.Name -eq $targetRDPFileName -and $file.FullName -notin $processedFiles) {
                    Write-Host "Target file detected: $($file.Name) at $(Get-Date -Format 'HH:mm:ss')"
                    Write-Host "Full path: $($file.FullName)"
                    
                    Start-Sleep -Seconds 2
                    
                    try {
                        Write-Host "Executing RDP file: $($file.FullName)"
                        
                        # If credentials provided, cache them and modify RDP file
                        if ($RDPUsername -and $RDPPassword) {
                            Write-Host "Caching credentials for: $RDPServer"
                            
                            # Cache credentials using cmdkey (more reliable than embedding in RDP)
                            $cmdkeyCmd = "cmdkey.exe /generic:$RDPServer /user:$RDPUsername /pass:$RDPPassword"
                            Invoke-Expression $cmdkeyCmd | Out-Null
                            Write-Host "Credentials cached successfully"
                            
                            # Read original RDP file
                            $rdpContent = Get-Content -Path $file.FullName -Encoding ASCII
                            
                            # Remove or disable credential prompting settings
                            $rdpContent = $rdpContent -replace 'prompt for credentials:i:1', 'prompt for credentials:i:0'
                            $rdpContent = $rdpContent -replace 'promptcredentialonce:i:1', 'promptcredentialonce:i:0'
                            $rdpContent = $rdpContent -replace 'enablecredsspsupport:i:1', 'enablecredsspsupport:i:0'
                            
                            # Ensure username is set in RDP file
                            if ($rdpContent -notmatch 'username:s:') {
                                $rdpContent += "`r`nusername:s:$RDPUsername"
                            } else {
                                $rdpContent = $rdpContent -replace 'username:s:.*', "username:s:$RDPUsername"
                            }
                            
                            # Create temporary RDP file
                            $tempRDPPath = [System.IO.Path]::GetTempFileName() -replace '\.tmp$', '.rdp'
                            Set-Content -Path $tempRDPPath -Value $rdpContent -Encoding ASCII
                            Write-Host "Temporary RDP file created: $tempRDPPath"
                            
                            Start-Sleep -Seconds 1
                            
                            # Execute temporary RDP file with cached credentials
                            Start-Process -FilePath $tempRDPPath
                            $processedFiles += $file.FullName
                            Write-Host "Executed successfully with cached credentials"
                            
                            # Clean up temporary file after a delay
                            Start-Sleep -Seconds 3
                            Remove-Item -Path $tempRDPPath -Force -ErrorAction SilentlyContinue
                            Write-Host "Temporary RDP file cleaned up"
                        }
                        else {
                            # Execute without credentials modification
                            Write-Host "No credentials provided, executing original RDP file"
                            Start-Process -FilePath $file.FullName
                            $processedFiles += $file.FullName
                            Write-Host "Executed successfully"
                        }
                        
                        Start-Sleep -Seconds 1
                        Remove-Item -Path $file.FullName -Force
                        Write-Host "File deleted: $($file.FullName)"
                    }
                    catch {
                        Write-Error "Error executing RDP file: $($_.Exception.Message)"
                    }
                }
            }
        }
        else {
            Write-Host "Download folder not found: $downloadFolder"
        }
    }
    catch {
        Write-Error "Error during monitoring: $($_.Exception.Message)"
    }
    
    # For test mode, exit after one iteration
    if ($TestMode) {
        Write-Host "Test mode iteration complete. Exiting."
        break
    }
    
    # Normal mode: sleep before next iteration
    Start-Sleep -Seconds 2
}

Write-Host "RDP file monitor stopped at $(Get-Date -Format 'HH:mm:ss')"
Stop-Transcript -ErrorAction SilentlyContinue

最後に

RDP ファイルは中身はテキストなのでいろいろハックできます

2026年1月23日金曜日

ダウンロードフォルダを監視し RDP ファイルを自動で開く Powershell スクリプト

ダウンロードフォルダを監視し RDP ファイルを自動で開く Powershell スクリプト

概要

今の chrome ではできないので自作する必要があります

環境

  • Windows 11

ダウンロードフォルダを監視し特定の rdp ファイルが出現したら自動で実行する Powershell

  • vim monitor_rdp_file.ps1
param()

# Basic file logging to help diagnose scheduled task behavior
$logDir = Join-Path $env:LOCALAPPDATA "RDPFileMonitor"
if (-not (Test-Path $logDir)) {
    New-Item -Path $logDir -ItemType Directory -Force | Out-Null
}
$logPath = Join-Path $logDir "monitor.log"
# Emit a simple startup marker regardless of transcript support
("Started: " + (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')) | Out-File -FilePath (Join-Path $logDir 'started.txt') -Append -Encoding utf8
try {
    Start-Transcript -Path $logPath -Append -ErrorAction SilentlyContinue | Out-Null
} catch {}

$downloadFolder = [Environment]::GetFolderPath("UserProfile") + "\Downloads"
$targetRDPFileName = "your-rdp-filename.rdp"
$processedFiles = @()

Write-Host "Starting RDP file monitoring (polling method)"
Write-Host "Log: $logPath"
Write-Host "Target folder: $downloadFolder"
Write-Host "Target file name: $targetRDPFileName"
Write-Host "Checking every 2 seconds..."

while ($true) {
    try {
        if (Test-Path $downloadFolder) {
            $files = Get-ChildItem -Path $downloadFolder -Filter "*.rdp" -File
            
            foreach ($file in $files) {
                if ($file.Name -eq $targetRDPFileName -and $file.FullName -notin $processedFiles) {
                    Write-Host "Target file detected: $($file.Name) at $(Get-Date -Format 'HH:mm:ss')"
                    Write-Host "Full path: $($file.FullName)"
                    
                    Start-Sleep -Seconds 2
                    
                    try {
                        Write-Host "Executing RDP file: $($file.FullName)"
                        # Use Start-Process for reliability in scheduled tasks
                        Start-Process -FilePath $file.FullName
                        $processedFiles += $file.FullName
                        Write-Host "Executed successfully"
                        
                        Start-Sleep -Seconds 1
                        Remove-Item -Path $file.FullName -Force
                        Write-Host "File deleted: $($file.FullName)"
                    }
                    catch {
                        Write-Error "Error executing RDP file: $($_.Exception.Message)"
                    }
                }
            }
        }
    }
    catch {
        Write-Error "Error during monitoring: $($_.Exception.Message)"
    }
    
    Start-Sleep -Seconds 2
}
finally {
    try { Stop-Transcript | Out-Null } catch {}
}

上記ファイルを実行する bat ファイル

権限を付与して実行する必要があるのでラッパー用のバッチファイルを作成します

  • vim monitor_rdp_file.bat
@echo off
REM This batch file launches the RDP file monitor PowerShell script
REM It will be called by Task Scheduler at user login

REM Ensure we start in the script directory (useful for relative paths)
pushd "C:\Users\username\path\to\powershell_script\"

REM Prepare simple logs for troubleshooting
set "LOGDIR=%LOCALAPPDATA%\RDPFileMonitor"
if not exist "%LOGDIR%" mkdir "%LOGDIR%" >nul 2>&1

REM Launch the PowerShell monitor hidden with execution policy bypass and redirect output to logs
powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "C:\Users\username\path\to\powershell_script\monitor_rdp_file.ps1" 1>>"%LOGDIR%\ps_out.log" 2>>"%LOGDIR%\ps_err.log"

popd
exit /b 0

バッチファイルをタスクスケジューラに登録する Powershell

タスクスケジューラで動かす場合はバッチファイルを登録します

  • vim register_scheduled_task.ps1
# Create scheduled task for RDP file monitor at user login
# This script should be run with administrator privileges

$taskName = "RDP File Monitor"
$taskPath = "\"
$scriptPath = "C:\Users\username\path\to\powershell_script\monitor_rdp_file.bat"

Write-Host "Creating scheduled task for RDP file monitor..."

# Check if task already exists
$existingTask = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue

if ($existingTask) {
    Write-Host "Task already exists. Removing..."
    Unregister-ScheduledTask -TaskName $taskName -Confirm:$false
}

# Create task trigger (at user login)
$trigger = New-ScheduledTaskTrigger -AtLogOn

# Create task action
$workingDir = Split-Path -Path $scriptPath -Parent
$action = New-ScheduledTaskAction -Execute "cmd.exe" -Argument "/c `"$scriptPath`"" -WorkingDirectory $workingDir

# Create task settings
$settings = New-ScheduledTaskSettingsSet -MultipleInstances IgnoreNew -StartWhenAvailable

# Register the task with highest privilege
$principal = New-ScheduledTaskPrincipal -UserId "$env:USERNAME" -RunLevel Highest -LogonType Interactive

Register-ScheduledTask -TaskName $taskName -Trigger $trigger -Action $action -Settings $settings -Principal $principal -Force

Write-Host "Task created successfully!"
Write-Host "Task name: $taskName"
Write-Host "Batch file: $scriptPath"
Write-Host "Trigger: At user login"
Write-Host ""
Write-Host "The task will now run automatically when you log in to Windows."

タスクスケジューラ登録

Start-Process powershell.exe -ArgumentList "-ExecutionPolicy Bypass -Command `"& 'C:\Users\username\path\to\powershell_script\register_scheduled_task.ps1'`"" -Verb RunAs -Wait

最後に

これでログインすると自動で起動し監視を開始します
cmdkey などと組み合わせると自動でログインまでしてくれます
ただ rdp ファイルの prompt for credentials:i:1 が 0 になっていないとダメです
(1 でも自動入力する方法はないのだろうか)

2023年10月10日火曜日

PowershellでGoogle日本語キーボードをインストールする方法

PowershellでGoogle日本語キーボードをインストールする方法

概要

この現象で日本語キーボードがなくなってしまうのでPowershellで自動インストールしてみます

環境

  • Windows 10

Google日本語キーボードを追加するスクリプト

# Get-WinUserLanguageList
$LanguageList = New-WinUserLanguageList ja-JP
$LanguageList[0].InputMethodTips.Clear()
$LanguageList[0].InputMethodTips.Add('0411:{D5A86FD5-5308-47EA-AD16-9C4EB160EC3C}{773EB24E-CA1D-4B1B-B420-FA985BB0B80D}')
Set-WinUserLanguageList $LanguageList -Force

説明

0411:{D5A86FD5-5308-47EA-AD16-9C4EB160EC3C}{773EB24E-CA1D-4B1B-B420-FA985BB0B80D} は Google 日本語キーボードのレイアウトコードになります

レイアウトコードは Get-WinUserLanguageList コマンドで確認できるので違う場合は上記コマンドで確認してください

一旦不要なキーボードを Clear で削除して再度 Google 日本語キーボードをインストールしているので最終的には日本語キーボードは Google 日本語キーボードのみになります

実行

実行方法やショートカットの作成はこちらを参考にしてください

直接実行はコマンドプロントからクリックで実行はショートカットを作成してください

最後に

なぜかなくなってしまうキーボードレイアウト問題はこれですべて解決です

2020年2月12日水曜日

VMware PowerCLI で nfs のマウント操作をしてみた

概要

VMware.PowerCLI で nfs のデータストアをマウントする操作をしてみました
サンプルのコマンドレットを紹介します

環境

  • CentOS 7.7.1908
  • .NET SDK 3.1
  • PowerShell 6.2.3
  • VMware.PowerCLI 11.5.0.14912921

データストアを追加する (マウント)

  • Connect-VIServer -Server 192.168.100.10 -User administrator@vsphere.local -Password xxxxxxxx
  • $host1 = Get-VMhost -Name 192.168.100.11
  • New-Datastore -Name nfs_test -Nfs -NfsHost 192.168.100.20 -Path /opt/nfs -VMHost $host1

データストアを削除する (アンマウント)

  • Remove-Datastore -Datastore nfs_test -VMHost $host1 -Confirm:$false

データストアの一覧を表示する

  • Get-Datastore

参考サイト

2020年2月10日月曜日

VMware PowerCLI でポートグループを操作するサンプル

概要

VMware.PowerCLI でポートグループを操作してみました
サンプルのコマンドレットを紹介します

環境

  • CentOS 7.7.1908
  • .NET SDK 3.1
  • PowerShell 6.2.3
  • VMware.PowerCLI 11.5.0.14912921

指定の vDS 配下にポートグループを作成する

  • New-VDPortgroup -VDSwitch vds -name pg -NumPorts 123 -VlanId 456

ポートグループを削除する

  • Get-VDPortGroup -Name pg | Remove-VDPortGroup

ポートグループのセキュリティポリシーを変更する

  • $pg = New-VDPortgroup -VDSwitch vds -name pg -NumPorts 123 -VlanId 456
  • $pg | Get-VDSecurityPolicy | Set-VDSecurityPolicy -AllowPromiscuous $true -MacChanges $true -ForgedTransmits $true

その他関連操作

  • Set-VDPortgroup
  • Export-VDPortgroup
  • Set-VDSecurityPolicy

参考サイト

2020年2月4日火曜日

VMware.PowerCLI でロールや権限周りの操作をしてみる

環境

  • CentOS 7.7.1908
  • .NET SDK 3.1
  • PowerShell 6.2.3
  • VMware.PowerCLI 11.5.0.14912921

Powershell の起動

以下は Powershell を起動したプロンプト内で実行します

証明書のエラーを抑制する

  • Set-PowerCLIConfiguration -InvalidCertificateAction:Ignore

一度のみ実行すれば OK です

vCenter or ESXi への接続 (basic 認証)

  • Connect-VIServer -Server 192.168.100.10 -User administrator@vsphere.local -Password xxxxxxxxxxx

vCenter or ESXi への接続解除

  • Disconnect-VIServer

ユーザの取得

  • Get-VMHostAccount
  • Get-VMHostAccount -Name hoge

ユーザの追加

  • New-VMHostAccount -Id hoge -Password "fuga12345!" -Description "for test"

ユーザの削除

  • Get-VMHostAccount -Id hoge | Remove-VMHostAccount

ロールの取得

  • Get-VIRole
  • Get-VIRole -Name NewRole_20200204

ロールの追加

  • New-VIRole -Name NewRole_20200204 -Privilege (Get-VIPrivilege -PrivilegeGroup)

ロールの削除

  • Get-VIRole -Name NewRole_20200204 | Remove-VIRole

権限の取得

  • Get-VIPermission
  • Get-VIPermission -Entity (Get-Datacenter) -Principal VSPHERE.LOCAL\vsphere-webclient-0c0e11a5-d914-4030-976c-04e51aa67b00

権限の追加 (ロール or ユーザへの権限割り当て)

  • New-VIPermission -Role NewRole_20200204 -Entity (Get-Datacenter) -Principal VSPHERE.LOCAL\vsphere-webclient-0c0e11a5-d914-4030-976c-04e51aa67
  • New-VIPermission -Entity (Get-VMHost) -Principal hoge -Role Admin -Propagate:$true

権限の削除

  • $permission = Get-VIPermission -Entity (Get-VMHost) -Principal hoge
  • Remove-VIPermission -Permission $permission

Tips

Get-View の使い方

  • $dc = Get-Datacenter | Get-View
  • Write-Host $dc.Name

Get-Datacenter で取得した結果から Datacenter オブジェクトを取得して編集に格納します
オブジェクトにすることでドットつなぎでフィールドなどを参照することができます

Select-Object -ExpandProperty

  • Get-VIPrivilege -Name System | Select-Object -ExpandProperty Id

デフォルトで表示されない Id フィールドを表示することができます
フィールドの一覧は Get-Member あたりで確認できます

  • Get-VIPrivilege | Get-Member

WhatIf (ドライラン)

  • Get-VIRole -Name NewRole_20200204 -WhatIf

どういう挙動になるのか確認することができます

Format-List で短縮形を表示する

  • Get-VIPermission | Format-List

長くて表示されない項目がある場合はフォーマットを指定することで表示できます

各コマンドのヘルプの表示

  • Get-Help Get-VIPermission
  • Get-Help Get-VIPermission -examples
  • Get-Help Get-VIPermission -full

最後に

VMware.PowerCLI でユーザ/ロール/権限周り操作をしてみました
Powershell に用意されているコマンドレットと組み合わせることで更に便利に扱うことができるようになります