#author("2024-10-23T01:24:02+09:00","default:admin","admin") #author("2024-10-23T01:41:51+09:00","default:admin","admin") #navi(../) #Contents ------------------------ *Powershell [#cbb330d1] ** モジュール関連 [#td02f412] *** モジュールをインストール [#qce43968] インストールされているモジュールをインストールする方法 PS> Install-Module -Name <モジュール名> *** モジュールを表示 [#ifb92fb8] インストールされているモジュールを表示 PS> Get-Module *** モジュールをインポート [#k1a7f368] モジュールをインポートする方法 PS> Import-Module <module-name> *** モジュールを削除 [#u9980c89] モジュールを削除する方法 PS> Remove-Module <module-name> ** hoge [#c3111dbc] cd D:\script $TargetFile = "D:\script\wrk\production\dat\product\product_20201001\wiki-001.zip" D:\script\wrk\deveroper\dat\product\product_20201001\wiki "D:\script\bin\7z.exe" e -y -o $filelist = (Get-ChildItem D:\script\wrk\production\dat\ -Recurse | ? { ! $_.PSIsContainer }).fullname $TargetFile = New-Object PSObject | Select-Object drive, folder1, folder2, folder3, folder4, folder5, folder6, file $Data = @() foreach ( $file in $filelist ) { $TargetFile = ($file).split("\") $Data += $TargetFile echo $TargetFile echo --- } $Data *** ディスク容量を確認する関数 [#ba7cade9] 関数: function Global:Get-DirSize() { Param( [string]$TargetDir ) if ( $TargetDir.Length -eq 0 ) { $Host.UI.WriteErrorLine( "Usage: Get-DirSize <path>" ) return } write-output ( "---------------------------------------------------------------------------------------------------" ) write-output ( "TargetDirectory : ${TargetDir}" ) write-output ( "---------------------------------------------------------------------------------------------------" ) set-location ${TargetDir} Get-ChildItem | Select-Object FullName, @{ name = "Size(MB)"; expression = { [math]::round((Get-ChildItem $_.FullName -Recurse -Force | Measure-Object Length -Sum ).Sum /1MB ) } } } 関数実行: PS C:\> Get-DirSize C:\ 実行結果: --------------------------------------------------------------------------------------------------- TargetDirectory : C:\ --------------------------------------------------------------------------------------------------- FullName Size(MB) -------- -------- C:\Autodesk 4997 C:\BUFFALO 101 C:\ESD 0 C:\Intel 0 C:\PerfLogs 0 C:\Program Files 3256 C:\Program Fi... 7851 C:\Users 257541 C:\VNTApp 0 C:\Windows 27189 PS C:\> *** バッテリー情報収集 [#l4f68f36] ##################################################################### # システム情報 ##################################################################### function QueryServerInfo(){ $ReturnData = New-Object PSObject | Select-Object HostName,Manufacturer,Model,SN,CPUName,PhysicalCores,Sockets,MemorySize,DiskInfos,OS $Win32_BIOS = Get-WmiObject Win32_BIOS $Win32_Processor = Get-WmiObject Win32_Processor $Win32_ComputerSystem = Get-WmiObject Win32_ComputerSystem $Win32_OperatingSystem = Get-WmiObject Win32_OperatingSystem # ホスト名 $ReturnData.HostName = hostname # メーカー名 $ReturnData.Manufacturer = $Win32_BIOS.Manufacturer # モデル名 $ReturnData.Model = $Win32_ComputerSystem.Model # シリアル番号 $ReturnData.SN = $Win32_BIOS.SerialNumber # CPU 名 $ReturnData.CPUName = @($Win32_Processor.Name)[0] # 物理コア数 $PhysicalCores = 0 $Win32_Processor.NumberOfCores | % { $PhysicalCores += $_} $ReturnData.PhysicalCores = $PhysicalCores # ソケット数 $ReturnData.Sockets = $Win32_ComputerSystem.NumberOfProcessors # メモリーサイズ(GB) $Total = 0 Get-WmiObject -Class Win32_PhysicalMemory | % {$Total += $_.Capacity} $ReturnData.MemorySize = [int]($Total/1GB) # ディスク情報 [array]$DiskDrives = Get-WmiObject Win32_DiskDrive | ? {$_.Caption -notmatch "Msft"} | sort Index $DiskInfos = @() foreach( $DiskDrive in $DiskDrives ){ $DiskInfo = New-Object PSObject | Select-Object Index, DiskSize $DiskInfo.Index = $DiskDrive.Index # ディスク番号 $DiskInfo.DiskSize = [int]($DiskDrive.Size/1GB) # ディスクサイズ(GB) $DiskInfos += $DiskInfo } $ReturnData.DiskInfos = $DiskInfos # OS $OS = $Win32_OperatingSystem.Caption $SP = $Win32_OperatingSystem.ServicePackMajorVersion if( $SP -ne 0 ){ $OS += "SP" + $SP } $ReturnData.OS = $OS return $ReturnData } powercfg /batteryreport |項目|説明|h |Installed batteries|バッテリー状態| |Recent usage|最近の使用状態(過去3日間)| |Battery usage|バッテリーの使用状態(過去3日間の電池残量)| |Usage history|使用状態履歴| |Battery capacity history|バッテリーキャパシティ履歴| |Battery life estimates|使用状況から推測したバッテリー稼働可能時間| **連想配列(Hashtable)メモ [#l902aa22] *** 配列作成 [#l20c9713] System.Collections.Hashtableのインスタンスを作成 $RadioButtons = @{} *** 連想配列(代入) [#o1e3c315] PS C:> $RadioButtons = @{ 1 = "AAA"; 2 = "BBB"; 3 = "CCC"; } *** 連想配列(表示) [#o14c06ce] PS C:> for($i=0; $i -le 3; $i++) { $RadioButtons.${i} = "AAA${i}" } PS C:> $RadioButton = "" PS C:> foreach ($RadioButton in $RadioButtons) { $RadioButton } Name Value ---- ----- 3 AAA3 2 AAA2 1 AAA1 0 AAA0 *** 繰り返し処理[#k4696ce0] foreachでループ処理するとき。ValuesプロパティにValueのコレクション、KeysプロパティにKeyのコレクションが入っている。 PS C:> $RadioButtons.Values | foreach { $_ } AAA3 AAA2 AAA1 AAA0 *** 繰り返し処理2[#s343141a] Valueを連想配列にして、値を取得する例。 PS C:> $dialog1 = @{ "Text" = "Dialog1"; "Size" = @{ "Width" = 600; "Height" = 400; }; } PS C:> $dialog1.Size.Width 600 PS C:> $dialog1.Values | foreach { $_ } Dialog1 Name Value ---- ----- Height 400 Width 600 PS C:> $dialog1.Keys | foreach { $_ } Text Size -フォルダーサイズ一覧~ [[フォルダーサイズ一覧>FrontPage/IT/Script/Windows/Powershell/FolderSize]] -ログイン状態確認 # ログファイルのパスを設定 $logFilePath = "C:\Logs\UserLogonStatus.log" # ログファイルが存在しない場合は作成 if (-Not (Test-Path $logFilePath)) { New-Item -Path $logFilePath -ItemType File -Force } # 現在ログオンしているユーザーを取得 $loggedOnUsers = Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty UserName # ログオン状態をログファイルに出力 $timeStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" if ($loggedOnUsers) { $logEntry = "$timeStamp - Logged on user: $loggedOnUsers" } else { $logEntry = "$timeStamp - No users logged on" } Add-Content -Path $logFilePath -Value $logEntry -administrator~ 「Administrator」でログインしている場合に「No users logged on」と表示される問題は、Win32_ComputerSystemクラスを使用しているためです。このクラスは「インタラクティブなユーザーセッション」を取得しますが、Administratorのセッションは特別なセキュリティコンテキストにあるため、正しく検出できない場合があります。~ ~ この問題を解決するには、別の方法でログオンユーザーを取得することが必要です。以下の方法を試してみてください。~ ~ 修正版スクリプト qwinstaコマンドを使用して、ログオンしているすべてのセッションを取得し、ユーザー名を判別する方法です。これにより、ローカルにログインしているすべてのユーザーを確認でき、Administratorも含まれます。~ powershell # ログファイルのパスを設定 $logFilePath = "C:\Logs\UserLogonStatus.log" # ログファイルが存在しない場合は作成 if (-Not (Test-Path $logFilePath)) { New-Item -Path $logFilePath -ItemType File -Force } # qwinstaコマンドを実行してセッション情報を取得 $sessionInfo = qwinsta | Select-String "Active" | ForEach-Object { ($_ -split "\s+")[1] } # ログオンしているユーザーを取得 $loggedOnUsers = $sessionInfo -join ", " # ログオン状態をログファイルに出力 $timeStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" if ($loggedOnUsers) { $logEntry = "$timeStamp - Logged on users: $loggedOnUsers" } else { $logEntry = "$timeStamp - No users logged on" } # ログファイルに出力 Add-Content -Path $logFilePath -Value $logEntry スクリプトの説明 -qwinstaは、Windows上で現在アクティブなセッションをリストするコマンドです。このコマンドは、インタラクティブなユーザー(例:Administratorを含む)のセッションも取得します。~ -Select-String "Active"で、アクティブなセッションのみをフィルタリングしています。~ -その後、ユーザー名を抽出し、それをログファイルに記録しています。~ 手順 +上記の修正版スクリプトをPowerShellスクリプトファイル(例:CheckUserLogon.ps1)として保存します。~ +タスクスケジューラで、このスクリプトを定期的に実行するタスクを設定します(前述の手順を参考にしてください)。~ これで、Administratorでログインしている場合でも正しくログオンユーザーが取得され、ログに記録されるはずです。 -パート2 qwinstaコマンドを使うと、リモートデスクトップ(RDP)セッションでログインしているユーザーが「rdp-tcp#6」のように表示されることがあります。これは、RDPセッションに割り当てられたセッションIDが表示されるためで、具体的なユーザー名ではありません。このようなセッションIDから実際のユーザー名を取得するためには、quserコマンドやGet-WmiObjectなどを組み合わせて使う方法があります。~ ~ 解決策: quser コマンドを使用してユーザー名を取得する~ quserコマンドを使うと、現在ログオンしているユーザーとそのセッションのリストを取得でき、rdp-tcpのセッションでもユーザー名を確認できます。~ ~ 以下は、RDPセッションやローカルセッションも含めて正確にログオンユーザーを取得するスクリプトの例です。~ ~ 修正版スクリプト~ powershell # ログファイルのパスを設定 $logFilePath = "C:\Logs\UserLogonStatus.log" # ログファイルが存在しない場合は作成 if (-Not (Test-Path $logFilePath)) { New-Item -Path $logFilePath -ItemType File -Force } # quserコマンドでセッション情報を取得 $sessionInfo = quser | ForEach-Object { # 行を分割し、ユーザー名を取得 ($_ -split "\s+")[1] } # ユーザーがログオンしているか確認 $loggedOnUsers = $sessionInfo | Where-Object { $_ -ne "USERNAME" } # "USERNAME" ヘッダーを除外 # ログオン状態をログファイルに出力 $timeStamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" if ($loggedOnUsers) { $logEntry = "$timeStamp - Logged on users: $($loggedOnUsers -join ', ')" } else { $logEntry = "$timeStamp - No users logged on" } # ログファイルに出力 Add-Content -Path $logFilePath -Value $logEntry スクリプトのポイント +quserコマンド:~ quserコマンドは、現在ログオンしているすべてのユーザーとそのセッション情報を表示します。この出力から、実際のユーザー名を抽出します。~ ~ +ForEach-Objectでユーザー名の抽出:~ 出力行を空白で分割し、必要なユーザー名部分だけを取得します。~ ~ +ヘッダーを除外:~ quserコマンドの出力には「USERNAME」というヘッダー行があります。この行を除外して、実際のユーザー名だけを取り出します。~ ~ 使い方~ +スクリプトをファイルとして保存(例:CheckRDPUserLogon.ps1)。~ +前述のタスクスケジューラの設定方法に従い、定期的に実行するよう設定します。~ これにより、RDPセッションも含め、正しくログオンユーザー(Administratorやその他のユーザー)が取得され、ログファイルに出力されるようになります。 ~ 結果例~ ログファイルには以下のように記録されます:~ ~ bash~ コードをコピーする~ 2024-10-18 12:30:00 - Logged on users: Administrator, JohnDoe~ これで、RDPセッションで「rdp-tcp#6」などの表示ではなく、実際にログオンしているユーザー名が表示されるようになります。~ **GUI ツール [#l0f7168a] ***リモートサーバへスクリプトを設置するGUIプログラム [#l1ad7878] Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing # フォームの作成 $form = New-Object System.Windows.Forms.Form $form.Text = "リモート接続とファイル設置" $form.Size = New-Object System.Drawing.Size(400,300) $form.StartPosition = "CenterScreen" # ラベルとテキストボックス $labelHost = New-Object System.Windows.Forms.Label $labelHost.Text = "ホスト名:" $labelHost.Location = New-Object System.Drawing.Point(10,20) $form.Controls.Add($labelHost) $textHost = New-Object System.Windows.Forms.TextBox $textHost.Location = New-Object System.Drawing.Point(120,20) $textHost.Width = 250 $form.Controls.Add($textHost) $labelUser = New-Object System.Windows.Forms.Label $labelUser.Text = "ユーザー名:" $labelUser.Location = New-Object System.Drawing.Point(10,60) $form.Controls.Add($labelUser) $textUser = New-Object System.Windows.Forms.TextBox $textUser.Location = New-Object System.Drawing.Point(120,60) $textUser.Width = 250 $form.Controls.Add($textUser) $labelPassword = New-Object System.Windows.Forms.Label $labelPassword.Text = "パスワード:" $labelPassword.Location = New-Object System.Drawing.Point(10,100) $form.Controls.Add($labelPassword) $textPassword = New-Object System.Windows.Forms.TextBox $textPassword.Location = New-Object System.Drawing.Point(120,100) $textPassword.Width = 250 $textPassword.UseSystemPasswordChar = $true $form.Controls.Add($textPassword) $labelFile = New-Object System.Windows.Forms.Label $labelFile.Text = "ファイル選択:" $labelFile.Location = New-Object System.Drawing.Point(10,140) $form.Controls.Add($labelFile) $textFile = New-Object System.Windows.Forms.TextBox $textFile.Location = New-Object System.Drawing.Point(120,140) $textFile.Width = 180 $form.Controls.Add($textFile) $buttonBrowse = New-Object System.Windows.Forms.Button $buttonBrowse.Text = "参照..." $buttonBrowse.Location = New-Object System.Drawing.Point(310,140) $buttonBrowse.Add_Click({ $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog if ($openFileDialog.ShowDialog() -eq 'OK') { $textFile.Text = $openFileDialog.FileName } }) $form.Controls.Add($buttonBrowse) # 接続ボタン $buttonConnect = New-Object System.Windows.Forms.Button $buttonConnect.Text = "接続" $buttonConnect.Location = New-Object System.Drawing.Point(150,180) $form.Controls.Add($buttonConnect) # 終了ボタン $buttonExit = New-Object System.Windows.Forms.Button $buttonExit.Text = "終了" $buttonExit.Location = New-Object System.Drawing.Point(250,180) $buttonExit.Add_Click({ $form.Close() }) $form.Controls.Add($buttonExit) $buttonConnect.Add_Click({ $hostName = $textHost.Text $userName = $textUser.Text $password = $textPassword.Text | ConvertTo-SecureString -AsPlainText -Force $credential = New-Object System.Management.Automation.PSCredential ($userName, $password) # リモートセッションの作成 try { $session = New-PSSession -ComputerName $hostName -Credential $credential if ($session -ne $null) { [System.Windows.Forms.MessageBox]::Show("接続成功しました!") # ファイル転送処理 $filePath = $textFile.Text if (Test-Path $filePath) { Copy-Item -Path $filePath -Destination "C:\RemotePath" -ToSession $session [System.Windows.Forms.MessageBox]::Show("ファイルを転送しました。") } else { [System.Windows.Forms.MessageBox]::Show("ファイルが見つかりません。") } # セッションの終了 Remove-PSSession -Session $session } else { [System.Windows.Forms.MessageBox]::Show("セッション確立に失敗しました。") } } catch { [System.Windows.Forms.MessageBox]::Show("エラー: $_") } }) $form.Topmost = $true $form.Add_Shown({$form.Activate()}) [void]$form.ShowDialog() **参考資料 [#je7bc608] -[[ChatGPT>https://chatgpt.com/]]