SHIMSOFT-Fundamentals.psm1
function Get-PropertyNames { <# .SYNOPSIS オブジェクト配列からプロパティ名を取得します。 .DESCRIPTION オブジェクト配列からプロパティ名を取得します。 構成要素の異なるオブジェクトの配列から、すべてのプロパティ名を取得します。 .EXAMPLE Get-PropertyName -Array $Array .EXAMPLE Get-PropertyName -Array $Array .EXAMPLE $Array | Get-PropertyName .EXAMPLE $Array | ft -Property (Get-PropertyName -Array $Array) .PARAMETER Array オブジェクト配列を指定してください。 .LINK .NOTES .INPUTS パイプラインからの入力可能です。 .OUTPUTS 文字列 #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Always multiple results.")] param( [Parameter(Mandatory=$false,Position=1,ValueFromPipeLine=$True)] [Array]$Array ) begin { $PropertyNames = @() } process { foreach ($A in $Array) { $PropertyNames += ($A | Get-Member -MemberType Properties -ErrorAction SilentlyContinue).Name } } end { ($PropertyNames | Sort-Object -Unique) } } function Get-MSProductLifeCycle { <# .SYNOPSIS マイクロソフト社製品の製品名からライフサイクル情報を確認します。 .DESCRIPTION マイクロソフト社製品の製品名からライフサイクル情報を確認します。 https://app-omaha-prod.azurewebsites.net/api/PublishedListings/Export(endOfSupportYear=0,endOfSupportMonths=0,family=%27%27,group=%27%27) インターネットに接続できない環境の場合は利用できません。 処理のため、モジュール実態フォルダ内に以下の3個のデータファイルが保存されます。 ・Microsoft 社 Web サイトからダウンロードした Excel ファイル ・Excel ファイルを CSV 変換した CSV ファイル ・CSV ファイルを処理に合わせて成型した XML ファイル .EXAMPLE Windows Server 2016 について確認したい場合。 Get-MSProductLifeCycle -Product "Windows Server 2016" .EXAMPLE Microsoft Product Life Cycle リストを強制的にリフレッシュしたい場合。 Get-MSProductLifeCycle -Refresh .EXAMPLE Microsoft Product Life Cycle リストをリフレッシュを抑制したい場合。 Get-MSProductLifeCycle -Product "Windows Server 2016" -NoRefresh ただし、処理に必要なデータファイルがそろっていない場合はリフレッシュ動作は強制されます。 .EXAMPLE 2022年中にメインストリームサポートが終了する製品を確認したい。 Get-MSProductLifeCycle -Product * | where {$_.MainstreamDate -ge "2022/01/01" -and $_.MainstreamDate -le "2022/12/31"} .EXAMPLE 2022年中に延長サポートが終了する製品を確認したい。 Get-MSProductLifeCycle -Product * | where {$_.ExtendedEndDateDate -ge "2022/01/01" -and $_.ExtendedEndDate -le "2022/12/31"} .EXAMPLE 2022年中にモダンサイクルポリシー製品の提供が終了する製品を確認したい。 Get-MSProductLifeCycle -Product * | where {$_.RetirementDate -ge "2022/01/01" -and $_.RetirementDate -le "2022/12/31"} .PARAMETER Product マイクロソフト製品名を指定します。半角スペースを含む場合は "Windows Server" のように指定します。 ワイルドカード指定できます。 "Exchange*2019" や "Windows 10*21H2" .PARAMETER Refresh Life Cycle 情報を再ダウンロードし、キャッシュをリフレッシュします。 Life Cycle 情報が古い場合(タイムスタンプが今月ではない) 場合はこのオプション指定有無にかかわらず最新データへのリフレッシします。 データ再生成に時間がかかります。(ver 1.7 以前と比べ処理時間は高速化されました) .PARAMETER NoRefresh Life Cycle 情報が古い場合(タイムスタンプが今月ではない) 場合も最新データへのリフレッシュをスキップします。 インターネット通信できない環境や、データリフレッシュにかかる時間を節約したい場合に利用します。 ただし、処理に必要なデータファイルがそろっていない場合はリフレッシュ動作は強制されます。 .LINK .NOTES https://app-omaha-prod.azurewebsites.net/api/PublishedListings/Export(endOfSupportYear=0,endOfSupportMonths=0,family=%27%27,group=%27%27) の Web サイト利用は無許可利用です。 .INPUTS なし。パイプラインからの入力は受け付けません。 .OUTPUTS ダウンロードした CSV データから生成されたオブジェクトです。 #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "", Justification="Progress information")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "", Justification="Parameter used.")] Param( [Parameter(Mandatory=$false,Position=1)] [String]$Product="no-product", [Parameter(Mandatory=$false,Position=2)] [Switch]$Refresh, [Parameter(Mandatory=$false,Position=3)] [Switch]$NoRefresh ) $PLCExcel = "\ProductLifeCycle_SourceData.xlsx" $PLCCSV = "\ProductLifeCycle.csv" $PLCCache = "\ProductLifeCycle.xml" if ($True -eq $Refresh) { Write-Host ("go to Refresh Cache") $CacheActive = $False } else { $CacheActive = $true } if ($False -eq (Test-Path -Path ("{0}{1}" -f $PSScriptRoot,$PLCExcel)) -or $False -eq (Test-Path -Path ("{0}{1}" -f $PSScriptRoot,$PLCCache)) -or $False -eq (Test-Path -Path ("{0}{1}" -f $PSScriptRoot,$PLCCSV))) { $CacheActive = $False } else { $File = Get-ChildItem -Path ("{0}{1}" -f $PSScriptRoot,$PLCExcel) if ((Get-Date -Date $file.LastWriteTime -Format "yyyyMM") -ne (Get-Date -Format "yyyyMM")) { if ($False -eq $NoRefresh) { $CacheActive = $False } else { Write-Host ("Cache file is old but No Refresh.") } } } if ($False -eq $CacheActive) { # Refresh Cache Write-Host ("Downloading Microsoft Prodcut Life Cycle List.") Write-Verbose ("Downloading... {0}" -f (get-date -format "hh:mm:ss")) $WebCli = New-Object System.Net.WebClient $url ="https://app-omaha-prod.azurewebsites.net/api/PublishedListings/Export(endOfSupportYear=0,endOfSupportMonths=0,family=%27%27,group=%27%27)" $WebCli.DownloadFile($url, ("{0}{1}" -f $PSScriptRoot,$PLCExcel)) Write-Verbose ("Download Complete. {0}" -f (get-date -format "hh:mm:ss")) Write-Host ("Generate Cache File...") Write-Verbose ("Open Excel file. {0}" -f (get-date -format "hh:mm:ss")) $File = Get-ChildItem -Path ("{0}{1}" -f $PSScriptRoot,$PLCExcel) $Excel =New-Object -ComObject Excel.Application $Excel.DisplayAlerts=$false $book = $Excel.Workbooks.Open($File.FullName) # $Sheet = $Excel.Worksheets.Item(1) $work = $book.SaveAs(("{0}{1}" -f $PSScriptRoot,$PLCCSV),6) [void]$book.Close($false) [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($book) Write-Verbose (" Closed book. {0}" -f (get-date -format "hh:mm:ss")) [void]$Excel.Quit() [void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($Excel) Write-Verbose (" Closed Excel {0}" -f (get-date -format "hh:mm:ss")) if ($False -eq $Work) { Write-Error ("Can not SaveAs to CSV") break } Write-Verbose ("SaveAs CSV file. {0}" -f (get-date -format "hh:mm:ss")) $PLCwork = Get-Content -Path ("{0}{1}" -f $PSScriptRoot,$PLCCSV) -Encoding Default $PLCtitle = $PLCwork | Where-Object {$_ -like "Product,*"} $PLC = $PLCwork[($PLCwork.IndexOf($PLCtitle))..($PLCwork.Count-1)] | ConvertFrom-Csv Write-Verbose ("Column Title fetching... {0}" -f (get-date -format "hh:mm:ss")) $PropList = Get-PropertyNames -Array $PLC Write-Verbose ("Column Title fetch completed. {0}" -f (get-date -format "hh:mm:ss")) $ProductLifeCycle = @() Write-Verbose ("Records fetching... {0}" -f (get-date -format "hh:mm:ss")) foreach ($P in $PLC) { Write-Verbose (" Row Start. {0}" -f (get-date -format "hh:mm:ss")) $Mem = New-Object PSObject foreach ($Prop in $PropList) { if ($Prop -like "*Date" -and ("" -ne $P.($Prop))) { $Mem | Add-Member -MemberType NoteProperty -Name $Prop -Value (Get-Date -Date $P.($Prop) -Format "yyyy/MM/dd") } else { $Mem | Add-Member -MemberType NoteProperty -Name $Prop -Value $P.($Prop) } } $Mem | Add-Member -MemberType NoteProperty -Name ProductString -Value (@($Mem.Product,$Mem.Edition,$Mem.Release) -join " ") $ProductLifeCycle += $Mem Write-Verbose (" Row End. {0}" -f (get-date -format "hh:mm:ss")) } Write-Verbose ("Records fetch Completed and Close Excel. {0}" -f (get-date -format "hh:mm:ss")) $ProductLifeCycle | Export-Clixml -Path ("{0}{1}" -f $PSScriptRoot,$PLCCache) Write-Verbose ("Exported Cache file. {0}" -f (get-date -format "hh:mm:ss")) Write-Host ("Cache file created.") } else { Write-Verbose ("Using current cache file.") } $ProductLifeCycle = Import-Clixml -Path ("{0}{1}" -f $PSScriptRoot,$PLCCache) $Results = $ProductLifeCycle | Where-Object {$_.ProductString -like ("{0}*" -f $Product)} $defaultProperties = @("ProductString","MainstreamDate","ExtendedEndDate","RetirementDate") $defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet("DefaultDisplayPropertySet",[string[]]$defaultProperties) $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet) $Results | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers $Results } function ConvertTo-Narrow { <# .SYNOPSIS 全角文字列を半角文字列に変換します。 .DESCRIPTION 全角文字列を半角文字列に変換します。 すべての全角文字が半角に出来るわけではありません。 平仮名、片仮名、数字、アルファベットが変換できます。 全角平仮名は半角片仮名になります。 .EXAMPLE ConvertTo-Narrow -String "あいうえお" .EXAMPLE ConvertTo-Narrow -String "12345" .PARAMETER String 全角文字列を指定します。 .LINK .NOTES .INPUTS なし。パイプラインからの入力は受け付けません。 .OUTPUTS 半角に変換した文字列を返します。 #> Param( [Parameter(Mandatory=$true,Position=1)] [String]$String ) $a = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをんぁぃぅぇぉゃゅょっ0123456789" $a += "アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァィゥェォャュョッ" $a += "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" $a += "!#$%&()=~|-ー¥@{}「」[]【】〔〕`”`’`‘/*-+、,。.<>゛ ゜" $b = "アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァィゥェォャュョッ0123456789" $b += "アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァィゥェォャュョッ" $b += "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" $b += "!#`$%&()=~|-ー\@`{}[][][][]`"`'``/*-+,,..<>゙ ゚" $c = "ヴがぎぐげござじずぜぞだぢづでどばびぶべぼぱぴぷぺぽ" $c += "ヴガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポ" $d = "ヴガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポ" $d += "ヴガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポ" $Work = $String -Split "" $Work = $Work[1..($Work.Count-2)] $Result = "" foreach ($s in $Work) { if ($a.IndexOf($s) -ne -1) { # 普通の文字 $Result += $b[($a.IndexOf($s))] } else { if ($c.IndexOf($s) -ne -1) { # 濁音・半濁音 $Result += $d.Substring(($c.IndexOf($s)*2),2) } else { # 変換できない $Result += $s } } } $Result.Replace(" "," ") } function ConvertTo-Wide { <# .SYNOPSIS 半角文字列を全角文字列に変換します。 .DESCRIPTION 半角文字列を全角文字列に変換します。 すべての半角文字が全角に出来るわけではありません。 片仮名、数字、アルファベットが変換できます。 半角片仮名は全角片仮名になります。 .EXAMPLE ConverTo-Wide -String "アイウエオ" .EXAMPLE ConvertTo-Wide -String "12345" .PARAMETER String 全角文字列を指定します。 .LINK .NOTES .INPUTS なし。パイプラインからの入力は受け付けません。 .OUTPUTS 半角に変換した文字列を返します。 #> Param( [Parameter(Mandatory=$true,Position=1)] [String]$String ) $a = "アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァィゥェォャュョッ0123456789" $a += "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" $a += "!#$%&()=~|-ー¥@{}「」[]【】〔〕`”`’`‘/*-+、,。.<>゛ ゜" $b = "アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァィゥェォャュョッ0123456789" $b += "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" $b += "!#`$%&()=~|-ー\@`{}[][][][]`"`'``/*-+,,..<>゙ ゚" $c = "ヴガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポ" $d = "ヴガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポ" $Work = $String -Split "" $Work = $Work[1..($Work.Count-2)] $Result = "" $PreFetch = " " foreach ($s in $Work) { if ("゙ ゚".IndexOf($s) -ne -1 -and $d.IndexOf($PreFetch+$s) -ne -1) { $s = $PreFetch + $s $Result = $Result.Substring(0,$Result.Length-1) } if ($b.IndexOf($s) -ne -1) { # 普通の文字 $Result += $a[($b.IndexOf($s))] } else { if ($d.IndexOf($s) -ne -1) { # 濁音・半濁音 $Result += $c.Substring(($d.IndexOf($s)/2),1) } else { # 変換できない $Result += $s } } $PreFetch = $s } $Result.Replace(" "," ") } function Test-IsNumeric { <# .SYNOPSIS 指定した文字列が数値文字列か検証します。 数値文字列なら $True を、そうでないなら $False を返します。 数値文字列とは [int] などにキャスト変換できる文字列を指します。 .DESCRIPTION 指定した文字列が数値文字列か検証します。 数値文字列なら $True を、そうでないなら $False を返します。 .EXAMPLE Test-IsNumeric -String "100" 結果は $True .EXAMPLE Test-IsNumeric -String "123.4" 結果は $True .EXAMPLE Test-IsNumeric -String "1,234" 結果は $True .EXAMPLE Test-IsNumeric -String "123" 結果は $False 全角文字列は数値文字列とはみなされません。 .EXAMPLE Test-IsNumeric -String "123abc" 結果は $False .EXAMPLE Test-IsNumeric -String "百十五" 結果は $False .PARAMETER String 文字列を指定します。 .LINK .NOTES s .INPUTS なし。パイプラインからの入力は受け付けません。 .OUTPUTS 半角に変換した文字列を返します。 #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "", Justification="The variable Work is suprress output int value.")] Param( [Parameter(Mandatory=$true,Position=1)] [String]$String ) Try { $Work = [int]$String; $True } catch { $False } } function Format-WindowsFeature { <# .SYNOPSIS Get-WindowsFeature 実行したときのような結果を表示します。 .DESCRIPTION Get-WindowsFeature コマンドを実行した結果を保存しておきたいときに、 Get-WindowsFeature | Export-Clixml -Path WindowsFeature.xml として情報を保存したとします。 保存したファイルなどを別の環境で確認したい場合に、以下のようにしたとします。 $WF = Import-Clixml -Path WindowsFeature.xml $FW すると Get-WindowsFeature を実行したときのような結果が出ずにがっかりするんです。 そこで、 Format-WindowsFeature でもう一度あの表示を得ることができます。 .EXAMPLE Format-WindowsFeature -WindowsFeature (Import-Clixml -Path WindowsFeature.xml) .PARAMETER WindowsFeatures Get-WindowsFeatures の結果を指定します。 .LINK .NOTES s .INPUTS なし。パイプラインからの入力は受け付けません。 .OUTPUTS 半角に変換した文字列を返します。 #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "", Justification="The variable Work is suprress output int value.")] Param( [Parameter(Mandatory=$true,Position=1)] [Array]$WindowsFeature ) $WF_Object = @( "AdditionalInfo", "BestPracticesModelId", "DependsOn", "Depth", "Description", "DisplayName", "EventQuery", "FeatureType", "Installed", "InstallState", "Name", "Notification", "Parent", "Path", "PostConfigurationNeeded", "ServerComponentDescriptor", "SubFeatures", "SystemService") if ($WindowsFeature.GetType().BaseType.Name -ne "Array") { Write-Error "指定されたデータは Get-WindowsFeature の結果セットではありません。" break } $WF_Check = Get-PropertyNames -Array $WindowsFeature if ($WF_Check.Count -ne $WF_Object.Count) { Write-Error "指定されたデータは Get-WindowsFeature の結果セットではありません。" } $isFail = $false foreach ($CK in $WF_Check) { if ($WF_Object.IndexOf($CK) -eq -1) { Write-Error ("指定されたデータに不明なプロパティ値 {0} があります。" -f $CK) $isFail = $true } } if ($isFail) { break } foreach ($WF in $WindowsFeature) { Write-Output ("{0}[{1}] {2}" -f (" "*($WF.Depth-1)),(("X"* $WF.Installed) + (" " * !$WF.Installed)),$WF.DisplayName) } } Function Compare-ObjectProperties { <# .SYNOPSIS オブジェクトの一致性を確認します。 .DESCRIPTION オブジェクトの一致性を確認します。 戻り値として不一致のプロパティ一覧を返します。 戻り値が Null の場合、比較対象のオブジェクトは一致している可能性が濃厚です。 一致する項目は返されません。 戻り値に含まれる項目は以下の通りです。 PropertyName : 比較対象オブジェクトに含まれるプロパティの名前です。 RefValue : 参照側の値 RefExist : 参照側にプロパティが存在していたかどうか RefIsNull : 参照側が Null だったかどうか DiffValue : 比較側の値 DiffExist : 比較側にプロパティが存在していたかどうか DiffIsNull : 比較側が Null だったかどうか DiffType : 差異種別 オプションフィールド SubDiff : Deep 比較動作時に比較結果情報が含まれる。 DiffArray : プロパティタイプが ArrayList の時に比較参考値が含まれる。 DiffType の種類 <> : 両方に値が含まれ、相違している <=> : 両方に値が含まれ、相違している。そのプロパティ値以下の属性は一致していた。 <= : 参照側にのみ値が含まれている => : 比較側にのみ値が含まれている =//= : プロパティが ArrayList であり、アイテム数が同値であり、判定できない。 .EXAMPLE Compare-ObjectProperties -ReferenceObject $RefObj -DifferenceObject $DiffObj .EXAMPLE $Diff = Compare-ObjectProperties -ReferenceObject $RefObj -DifferenceObject $DiffObj if ($null -eq $Diff) { "一致" } else { "相違" } .EXAMPLE 比較除外したいプロパティ名がる場合、IgnoteProperties オプションを指定します。 Compare-ObjectProperties -ReferenceObject $RefObj -DifferenceObject $DiffObj -IgnoreProperties LastAccessTime,LastAccessTimeUtc あるオブジェクトで最終アクセス時間が異なることが予想されるが無視したい場合、IgnoreProperties オプションに指定すると比較除外されます。 無視したいプロパティ名が多数ある場合、配列変数に入れて渡すことが可能です。 $IgnoreProperties = @("LastAccessTime","LastAccessTimeUtc") Compare-ObjectProperties -ReferenceObject $RefObj -DifferenceObject $DiffObj -IgnoreProperties $IgnoreProperties .EXAMPLE 通常の比較で確認したい差異情報に辿り着かない場合、Deep オプションや Depth オプションを試みることができます。 オブジェクトのプロパティが階層的に情報を持つ場合、規定値で Depth 3 階層まで掘り下げて確認されます。 Depth 指定値を大きくすることでより深い階層の値を確認できる可能性があります。 処理時間がより多くかかります。 Compare-ObjectProperties -ReferenceObject $RefObj -DifferenceObject $DiffObj -Depth 4 通常比較で一致とされている部分でも Depp モードで比較することにより差異を見つけられる可能性があります。 処理時間がより多くかかります。 Compare-ObjectProperties -ReferenceObject $RefObj -DifferenceObject $DiffObj -Deep:$true .EXAMPLE プロパティのタイプが ArrayList の場合で、要素数が一致している場合同値と判断され (DiffType = =//=) た場合、 本当に一致していて確認不要の場合が多い見込みなので結果リストには含まれない様省略されます。 しかしながら、状況によりこのステータスの情報を確認したい場合があります。 その場合、IgnoreArrayNoDiffs オプションを $false に指定します。 Compare-ObjectProperties -ReferenceObject $RefObj -DifferenceObject $DiffObj -IgnoreArrayNoDiffs:$false .EXAMPLE Exchange Online 上で User1 と User2 メールボックスの設定値の差異を確認したい場合 あらかじめ Exchange Online に接続してあることを前提とした例を示します。 $RefMailbox = Get-Mailbox -Identity User1 $DiffMailbox = Get-Mailbox -Identity User2 Compare-ObjectProperties -ReferenceObject $RefMailbox -DifferenceObject $DiffMailbox .PARAMETER ReferenceObject 参照側オブジェクトを指定します。 .PARAMETER DifferenceObject 比較側オブジェクトを指定します。 .PARAMETER Deep Deep 比較モードを利用する場合、$True を指定します。規定値 $False です。 .PARAMETER IgnoreProperties 差異を気にしない無視してよいプロパティ名リストを指定します。 .PARAMETER Depth 階層的なプロパティ値を指定階層分掘り下げて比較します。規定値は 3 です。 .PARAMETER Prefix 内部的に利用します。階層的なプロパティを掘り下げ比較する際の親プロパティ名を保持します。 .PARAMETER IgnoreArrayNoDiffs プロパティのタイプが ArrayList のとき、参照側・比較側で要素数が一致する場合、おそらく同値 (DiffType = =//=) の場合に 結果リストに含めないように省略します。 これらを省略せず結果リストに含めたい場合 $False を指定します。 規定値 $True です。 .LINK .NOTES .INPUTS パイプラインからの入力出来ません。 .OUTPUTS 文字列 #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Always multiple results.")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidDefaultValueSwitchParameter", "", Justification="When specify False if nessesary.")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseProcessBlockForPipelineCommand", "", Justification="Not supported Pipeline Input")] param( [Parameter(Mandatory=$true,Position=1,ValueFromPipeLine=$False,ValueFromPipelineByPropertyName=$False)] $ReferenceObject, [Parameter(Mandatory=$true,Position=2,ValueFromPipeLine=$False,ValueFromPipelineByPropertyName=$False)] $DifferenceObject, [Parameter(Mandatory=$false,Position=3,ValueFromPipeLine=$False,ValueFromPipelineByPropertyName=$False)] [Boolean]$Deep=$false, [Parameter(Mandatory=$false,Position=4,ValueFromPipeLine=$False,ValueFromPipelineByPropertyName=$False)] [Array]$IgnoreProperties, [Parameter(Mandatory=$false,Position=5,ValueFromPipeLine=$False,ValueFromPipelineByPropertyName=$False)] [Int]$Depth=3, [Parameter(Mandatory=$false,Position=6,ValueFromPipeLine=$False,ValueFromPipelineByPropertyName=$False)] [String]$Prefix, [Parameter(Mandatory=$false,Position=7,ValueFromPipeLine=$False,ValueFromPipelineByPropertyName=$False)] [Switch]$IgnoreArrayNoDiffs=$True ) if (1 -eq $IgnoreProperties.Count) { $IgnoreProperties = @($IgnoreProperties[0].Split(","))} $RefPropName = Get-PropertyNames -Array $ReferenceObject $DiffPropName = Get-PropertyNames -Array $DifferenceObject $ComboPropName = ($RefPropName + $DiffPropName) | Sort-Object -Unique $DIFFS = @() foreach ($Prop in $ComboPropName) { Write-Verbose ("PropName : {0}.{1} // Depth : {2}" -f $Prefix,$Prop, $Depth) Write-Verbose (" {0} ;; {1}" -f $ReferenceObject.($Prop), $DifferenceObject.($Prop)) if ($Prop -notin $IgnoreProperties) { $isRefNull = $false $isDiffNull = $false if ($null -eq $ReferenceObject.($Prop)) { if ($null -eq $DifferenceObject.($Prop)) { Write-Verbose (" Equal both NULL") continue; } else { Write-Verbose (" Diff Ref NULL") $isRefNull = $true $DiffType ="=>" $Mem = New-Object PSObject if ("" -eq $Prefix) { $Mem | Add-Member -MemberType NoteProperty -Name PropertyName -Value $Prop } else { $Mem | Add-Member -MemberType NoteProperty -Name PropertyName -Value ("{0}.{1}" -f $Prefix,$Prop) } $Mem | Add-Member -MemberType NoteProperty -Name RefValue -Value $ReferenceObject.($Prop) $Mem | Add-Member -MemberType NoteProperty -Name RefExist -Value $true if (-1 -eq $RefPropName.IndexOf($Prop)) { Write-Verbose (" Not have Reference") $Mem.RefExist = $false $DiffType ="=>" } $Mem | Add-Member -MemberType NoteProperty -Name RefIsNull -Value $false if ($null -eq $RefPropName.IndexOf($Prop)) { $Mem.RefIsNull = $true } $Mem | Add-Member -MemberType NoteProperty -Name DiffValue -Value $DifferenceObject.($Prop) $Mem | Add-Member -MemberType NoteProperty -Name DiffExist -Value $true if (-1 -eq $DiffPropName.IndexOf($Prop)) { Write-Verbose (" Not have Difference") $Mem.DiffExist = $false $DiffType ="<=" } $Mem | Add-Member -MemberType NoteProperty -Name DiffIsNull -Value $false if ($null -eq $DiffPropName.IndexOf($Prop)) { $Mem.DiffIsNull = $true } $Mem | Add-Member -MemberType NoteProperty -Name DiffType -Value $DiffType $DIFFS += $Mem $DiffFlag = $false } } if ($null -ne $ReferenceObject.($Prop) -and $null -eq $DifferenceObject.($Prop)) { Write-Verbose (" Diff Diff NULL") $isDiffNull = $true $DiffType ="<=" $Mem = New-Object PSObject if ("" -eq $Prefix) { $Mem | Add-Member -MemberType NoteProperty -Name PropertyName -Value $Prop } else { $Mem | Add-Member -MemberType NoteProperty -Name PropertyName -Value ("{0}.{1}" -f $Prefix,$Prop) } $Mem | Add-Member -MemberType NoteProperty -Name RefValue -Value $ReferenceObject.($Prop) $Mem | Add-Member -MemberType NoteProperty -Name RefExist -Value $true if (-1 -eq $RefPropName.IndexOf($Prop)) { Write-Verbose (" Not have Reference") $Mem.RefExist = $false $DiffType ="=>" } $Mem | Add-Member -MemberType NoteProperty -Name RefIsNull -Value $false if ($null -eq $RefPropName.IndexOf($Prop)) { $Mem.RefIsNull = $true } $Mem | Add-Member -MemberType NoteProperty -Name DiffValue -Value $DifferenceObject.($Prop) $Mem | Add-Member -MemberType NoteProperty -Name DiffExist -Value $true if (-1 -eq $DiffPropName.IndexOf($Prop)) { Write-Verbose (" Not have Difference") $Mem.DiffExist = $false $DiffType ="<=" } $Mem | Add-Member -MemberType NoteProperty -Name DiffIsNull -Value $false if ($null -eq $DiffPropName.IndexOf($Prop)) { $Mem.DiffIsNull = $true } $Mem | Add-Member -MemberType NoteProperty -Name DiffType -Value $DiffType $DIFFS += $Mem $DiffFlag = $false } $isString = $false if ($false -eq $isRefNull -and $false -eq $isDiffNull) { if (($ReferenceObject.($Prop) | Get-Member -MemberType Method -ErrorAction SilentlyContinue | Where-Object {$_.Name -eq "toString"}).Count -eq 1 -and (($ReferenceObject.($Prop).GetType()).Name -ne "ArrayList")) { $isString = $true $DiffFlag = ($ReferenceObject.($Prop).toString() -eq $DifferenceObject.($Prop).toString()) } else { $DiffFlag = ($ReferenceObject.($Prop) -eq $DifferenceObject.($Prop)) } } if ($false -eq $DiffFlag) { Write-Verbose (" Diif String({0})" -f $isString) $DiffType ="<>" $Mem = New-Object PSObject if ("" -eq $Prefix) { $Mem | Add-Member -MemberType NoteProperty -Name PropertyName -Value $Prop } else { $Mem | Add-Member -MemberType NoteProperty -Name PropertyName -Value ("{0}.{1}" -f $Prefix,$Prop) } switch (($ReferenceObject.($Prop).GetType()).Name) { "ArrayList" { if (($ReferenceObject.($Prop).Count -eq 0) -and ($DifferenceObject.($Prop).Count -eq 0)) { $DIffType="==" } else { $DiffArray = Compare-Object -ReferenceObject $ReferenceObject.($Prop) -DifferenceObject $DifferenceObject.($Prop) $Mem | Add-Member -MemberType NoteProperty -Name DiffArray -Value $DiffArray if ($ReferenceObject.($Prop).Count -lt $DifferenceObject.($Prop).Count) { $DiffType="=>" } else { if ($ReferenceObject.($Prop).Count -gt $DifferenceObject.($Prop).Count) { $DiffType="<=" } else { $DiffType="=//=" if ($null -ne $DiffArray) { $DiffType="<>" } else { if ($True -eq $IgnoreArrayNoDiffs) { $DiffType="==" } } } } } } default { if ((($false -eq $isString) -or ($true -eq $Deep)) -and (($ReferenceObject.($Prop)|Get-Member -MemberType Properties -ErrorAction SilentlyContinue).Count -ge 1 -and (-1 -ne $RefPropName.IndexOf($Prop)) -and (-1 -ne $DiffPropName.IndexOf($Prop)))) { if ((0 -lt $Depth) -and -($false -eq $isRefNull) -and -($false -eq $isDiffNull)) { Write-Verbose (" go Deep") if ($null -eq $Prefix) { $SubDiff = Compare-ObjectProperties -ReferenceObject $ReferenceObject.($Prop) -DifferenceObject $DifferenceObject.($Prop) -Deep:$Deep -IgnoreProperties $IgnoreProperties -Depth ($Depth-1) -Prefix $Prop -IgnoreArrayNoDiffs:$IgnoreArrayNoDiffs } else { $SubDiff = Compare-ObjectProperties -ReferenceObject $ReferenceObject.($Prop) -DifferenceObject $DifferenceObject.($Prop) -Deep:$Deep -IgnoreProperties $IgnoreProperties -Depth ($Depth-1) -Prefix ("{0}.{1}" -f $Prefix,$Prop) -IgnoreArrayNoDiffs:$IgnoreArrayNoDiffs } } else { if ($false -eq $isRefNull -and $false -eq $isDiffNull) { if ($ReferenceObject.($Prop).toString() -ne $DifferenceObject.($Prop).toString()) { $SubMem = New-Object PSObject if ($null -eq $Prefix) { $SubMem | Add-Member -MemberType NoteProperty -Name PropertyName -Value $Prop } else { Write-Debug ("Check PropertyName") $SubMem | Add-Member -MemberType NoteProperty -Name PropertyName -Value ("{0}.{1}" -f $Prefix,$Prop) } $SubMem | Add-Member -MemberType NoteProperty -Name RefValue -Value $ReferenceObject.($Prop) $SubMem | Add-Member -MemberType NoteProperty -Name RefExist -Value $true $SubMem | Add-Member -MemberType NoteProperty -Name DiffValue -Value $DifferenceObject.($Prop) $SubMem | Add-Member -MemberType NoteProperty -Name DiffExist -Value $true $SubMem | Add-Member -MemberType NoteProperty -Name DiffType -Value "<>" $SubDiff = @($SubMem) } } } if (0 -eq $SubDiff.Count) { Write-Verbose (" Deep Equal") $DiffType = "<=>" if ($true -eq $isString -and $true -eq $DiffFlag) { $DiffType = "<>" Write-Verbose (" but Diff Reason toString") } } else { $Mem | Add-Member -MemberType NoteProperty -Name SubDiff -Value $SubDiff } } } } $Mem | Add-Member -MemberType NoteProperty -Name RefValue -Value $ReferenceObject.($Prop) $Mem | Add-Member -MemberType NoteProperty -Name RefExist -Value $true if (-1 -eq $RefPropName.IndexOf($Prop)) { Write-Verbose (" Not have Reference") $Mem.RefExist = $false $DiffType ="=>" } $Mem | Add-Member -MemberType NoteProperty -Name RefIsNull -Value $false if ($null -eq $RefPropName.IndexOf($Prop)) { $Mem.RefIsNull = $true } $Mem | Add-Member -MemberType NoteProperty -Name DiffValue -Value $DifferenceObject.($Prop) $Mem | Add-Member -MemberType NoteProperty -Name DiffExist -Value $true if (-1 -eq $DiffPropName.IndexOf($Prop)) { Write-Verbose (" Not have Difference") $Mem.DiffExist = $false $DiffType ="<=" } $Mem | Add-Member -MemberType NoteProperty -Name DiffIsNull -Value $false if ($null -eq $DiffPropName.IndexOf($Prop)) { $Mem.DiffIsNull = $true } $Mem | Add-Member -MemberType NoteProperty -Name DiffType -Value $DiffType if ("==" -ne $DiffType) { $DIFFS += $Mem } } else { Write-Verbose (" Equal") if ($True -eq $Deep -and ($ReferenceObject.($Prop)|Get-Member -MemberType Properties).Count -ge 1) { if (0 -lt $Depth) { Write-Verbose (" go Deep") if ("" -eq $Prefix) { $SubDiff = Compare-ObjectProperties -ReferenceObject $ReferenceObject.($Prop) -DifferenceObject $DifferenceObject.($Prop) -Deep $Deep -IgnoreProperties $IgnoreProperties -Depth ($Depth-1) -Prefix $Prop -IgnoreArrayNoDiffs:$IgnoreArrayNoDiffs } else { $SubDiff = Compare-ObjectProperties -ReferenceObject $ReferenceObject.($Prop) -DifferenceObject $DifferenceObject.($Prop) -Deep $Deep -IgnoreProperties $IgnoreProperties -Depth ($Depth-1) -Prefix ("{0}.{1}" -f $Prefix,$Prop) -IgnoreArrayNoDiffs:$IgnoreArrayNoDiffs } if (0 -ne $SubDiff.Count) { Write-Verbose (" Deep Diff") $DiffType ="<>" $Mem = New-Object PSObject $Mem | Add-Member -MemberType NoteProperty -Name PropertyName -Value $Prop $Mem | Add-Member -MemberType NoteProperty -Name SubDiff -Value $SubDiff $Mem | Add-Member -MemberType NoteProperty -Name RefValue -Value $ReferenceObject.($Prop) $Mem | Add-Member -MemberType NoteProperty -Name RefExist -Value $true $Mem | Add-Member -MemberType NoteProperty -Name DiffValue -Value $DifferenceObject.($Prop) $Mem | Add-Member -MemberType NoteProperty -Name DiffExist -Value $true $Mem | Add-Member -MemberType NoteProperty -Name DiffType -Value $DiffType $DIFFS += $Mem } } } } } else { Write-Verbose (" Ignored") } } $defaultProperties = @("PropertyName","DiffType","RefValue","DiffValue") $defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet("DefaultDisplayPropertySet",[string[]]$defaultProperties) $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet) $DIFFS | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers $DIFFS } Function Test-QuickConnect { <# .SYNOPSIS 対象 IP/ホスト名 へ 疎通テストを Test-NetConnection より高速に対処します。 .DESCRIPTION 対象 IP/ホスト名 へ 疎通テストを Test-NetConnection より高速に対処します。 .EXAMPLE Test-QuickConnect -ComputerName 192.168.10.100 -Port 443 -Timeout 100 指定された IP に対して 疎通をテストします。ping 疎通テストは行われません。 .EXAMPLE Test-QuickConnect -ComputerName 192.168.10.100 -Ping 指定された IP に対して 疎通をテストします。ping 疎通テストを行います。 .PARAMETER ComputerName 対象 IP/ホスト名 を指定して下さい。 .PARAMETER Port 疎通確認する TCP ポート番号を指定してください。 UDP ポートはテストできません。 .PARAMETER Timeout 疎通確認する際の Timeout 値 (milisec) を指定します。 既定値は 1000 です。 .LINK .NOTES .INPUTS パイプラインからの入力不可能です。 .OUTPUTS 文字列 #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Always multiple results.")] param( [Parameter(Mandatory=$true,Position=1)] [String]$ComputerName, [Parameter(Mandatory=$false,Position=2)] [Switch]$Ping, [Parameter(Mandatory=$false,Position=3)] [Int]$Port=0, [Parameter(Mandatory=$false,Position=4)] [Int]$Timeout=1000 ) $ReqCallback = $null $State = $null $TCPConnect = $False if (0 -eq $Port) { $Ping=$true } if ($True -eq $Ping) { $Mode="Ping" } else { $Mode="TCP" } if ($false -eq $Ping) { $Client = New-Object System.Net.Sockets.TcpClient $BeginConnect = $Client.BeginConnect($ComputerName,$Port,$ReqCallback,$State) Start-Sleep -Millisecond $Timeout if ($True -eq $Client.Connected) { $TCPConnect = $True } $BeginConnect = $Client.Close } else { $BeginConnect = ping -n 1 -w $Timeout $ComputerName | Where-Object { $_ -like "*=*ms*"} if ($null -ne $BeginConnect) { $TCPConnect = $True } } $Mem = New-Object PSObject $Mem | Add-Member -MemberType NoteProperty -Name ComputerName -Value $ComputerName $Mem | Add-Member -MemberType NoteProperty -Name Port -Value $Port $Mem | Add-Member -MemberType NoteProperty -Name Mode -Value $Mode $Mem | Add-Member -MemberType NoteProperty -Name TCPConnect -Value $TCPConnect Write-Output ($Mem) } Function Test-MultiPing { <# .SYNOPSIS 複数 IP へ ping 疎通テストします。 .DESCRIPTION 複数 IP へ ping 疎通テストします。 ポート番号指定がある場合、そのポートへの TCP 接続も確認します。 疎通結果を以下の記号で示します。 "o" = 疎通あり。接続可能。 "x" = 疎通なし。接続不可。 基本的にコンソールに結果を表示しますが、LogFile オプションを指定することで、並行してファイルに落とし込むことも可能です。 .EXAMPLE Test-MultiPing -IPList @("192.168.10.1","192.168.20.1","192.168.30.1","192.168.40.1") 指定された IP に対して Ping 疎通をテストします。 .EXAMPLE Test-MultiPing -IPList @("192.168.10.100","192.168.10.100:80","192.168.10.100:443") 指定された IP に対して Ping 疎通をテストします。 ポート番号指定されたものに対して該当ポートへの TCP 接続をテストします。 結果レポートには "192.168.10.100","192.168.10.100:80","192.168.10.100:443" をヘッダとして表示します。 .EXAMPLE Test-MultiPing -IPList @("192.168.10.100::Ping","192.168.10.100:80:HTTP","192.168.10.100:443:HTTPS") 指定された IP に対して Ping 疎通をテストします。 ポート番号指定されたものに対して該当ポートへの TCP 接続をテストします。 結果レポートには "Ping","HTTP","HTTPS" をヘッダとして表示します。 .EXAMPLE Test-MultiPing -IPList (Get-Content -Path .\IPList.txt) テキストファイルに 1 行 1 件 の対象指定を記載したファイルを読み込むことにより、 より多くのターゲット指定を容易にします。 また、テキストファイルにリストを記載しておくことによって再利用・再指定を容易にします。 テキストファイル内では 行頭"#" で始まるコメント行を付記できます。 テキストファイル内では 改行のみの空行を使用してリスト内を整理することができます。 コメント行、空行は疎通テストではスキップされます。 またレポートにも表示されません。 .EXAMPLE Test-MultiPing -IPList (Get-Content -Path .\IPList.txt) -LogFile .\PingResults.txt テスト結果を画面に表示するとともに、指定したログファイルに追記記録します。 ファイルが存在しない場合新規作成されます。 .EXAMPLE Test-MultiPing -IPList (Get-Content -Path .\IPList.txt) -LogFile .\PingResults.csv -CSV テスト結果を画面に表示するとともに、指定したログファイルに CSV 形式で記録します。 ファイルが存在しない場合新規作成されます。 .EXAMPLE Test-MultiPing -IPList (Get-Content -Path .\IPList.txt) -LogFile .\PingResults.txt -Append:$False テスト結果を画面に表示するとともに、指定したログファイルを新規作成し記録します。 .PARAMETER IPList 通信元 IPアドレスまたはホスト名の配列を指定して下さい。 指定できる形式は以下の通りです。 "Target:Port:FriendlyName" "Target" は IP アドレスまたはホスト名を指定します。 "Port" は TCP ポート番号を指定します。UDP はサポートしていません。 "FriendlyName" は結果に表示する名前を指定する場合に利用します。 "IP-Address" IP-Address に対して ping -n 1 をテストし疎通有無を確認します。 結果レポートには IP-Address をヘッダに表示されます。 "IP-Address::FriendlyName" IP-Address に対して ping -n 1 をテストし疎通有無を確認します。 結果レポートには FriendlyName をヘッダに表示されます。 "IP-Address:Port" IP-Address に対して Test-NetConnection -ComputerName IP-Address -Port Port のようなテストし疎通有無を確認します。 結果レポートには IP-Address:Port をヘッダに表示されます。 "IP-Address:Port:FriendlyName" IP-Address に対して Test-NetConnection -ComputerName IP-Address -Port Port のようなテストし疎通有無を確認します。 結果レポートには FriendlyName をヘッダに表示されます。 .PARAMETER NumOf 疎通テストの繰り返し回数を指定します。 既定値は 1000 です。 .PARAMETER Timeout 疎通テストのタイムアウト値 (milisecond) を指定します。 既定値は 1000 です。 .PARAMETER Height 結果レポートにヘッダを表示する間隔を指定します。 既定値は 5 です。 IPList に指定した対象数が Width 値を超えた場合、Height 1 に固定され、毎回ヘッダー表示が含まれるようになります。 LogFile 保存内容には影響せず、LogFile には先頭行にのみヘッダが記録されます。 .PARAMETER Width 結果レポートに並列表示する最大数を指定します。 既定値は 10 です。 IPList に指定した対象数が Width 値を超えた場合、テスト1回の結果が複数行に分割表示されます。 Height 1 に固定され、毎回ヘッダー表示が含まれるようになります。 LogFile 保存内容には影響せず、LogFile には全て 1 行で記録されます。 .PARAMETER DateTime 結果レポートの行に含まれるテスト回数 Count 値を、日時情報にします。 疎通 x から o に戻るまでの時間計測など必要な場合に便利です。 .PARAMETER LogFile 結果レポートを保存するファイル名を指定します。 指定ファイルが既に存在している場合、既定動作では追記になります。 ファイル再作成としたい場合は、 -Append:$False を指定してください。 記録データを CSV 形式としたい場合、CSV オプションを併用してください。 .PARAMETER CSV LogFile オプションと併用することで、記録を CSV 形式にします。 指定ファイルが既に存在している場合、既定動作では追記になります。 ファイル再作成としたい場合は、 -Append:$False を指定してください。 .PARAMETER Append LogFile ファイルは既定動作では追記になります。 ファイル再作成としたい場合は、 -Append:$False を指定してください。 .LINK .NOTES .INPUTS パイプラインからの入力不可能です。 .OUTPUTS 文字列 #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Always multiple results.")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidDefaultValueSwitchParameter", "", Justification="Always multiple results.")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseUsingScopeModifierInNewRunspaces", "", Justification="Always multiple results.")] param( [Parameter(Mandatory=$true,Position=1)] [Array]$IPList, [Parameter(Mandatory=$false,Position=2)] [Int]$NumOf=1000, [Parameter(Mandatory=$false,Position=3)] [Int]$Timeout=1000, [Parameter(Mandatory=$false,Position=4)] [Int]$Height=5, [Parameter(Mandatory=$false,Position=5)] [Int]$Width=10, [Parameter(Mandatory=$false,Position=6)] [Switch]$Datetime, [Parameter(Mandatory=$false,Position=7)] [String]$LogFile, [Parameter(Mandatory=$false,Position=8)] [Switch]$CSV, [Parameter(Mandatory=$false,Position=9)] [Switch]$Append=$True ) Write-Host ("Start pinging...") $isFirstTime = $True $IPList = $IPList | Where-Object {$_ -ne "" -and $_ -notlike "#*"} if ($Width -lt $IPList.Count) { $Height=1 } if (1 -eq $Height) { $EveryHeader = $True } else { $EveryHeader = $False } Try { for ($i=1; $i -lt $NumOf; $i++) { $Result = New-Object PSObject if ($True -eq $Datetime) { $Result | Add-Member -MemberType NoteProperty -Name "DateTime" -Value (Get-Date -Format "yyyy/MM/dd hh:mm:ss") } else { $Result | Add-Member -MemberType NoteProperty -Name "Count" -Value $i } $JobList = @() foreach ($IP in $IPList) { $JobList += Start-Job -Name $IP -ScriptBlock { param( [Parameter(Mandatory=$True,Position=1)] [String]$IP, [Parameter(Mandatory=$True,Position=2)] [Int]$Timeout ) $ReqCallback = $null $State = $null $TCPConnect = $False $Work = @($IP.Split(":")) if ("" -eq ($Work[1]+"")) { # ping $BeginConnect = ping -n 1 -w $Timeout $Work[0] | Where-Object { $_ -like "*=*ms*"} if ($null -ne $BeginConnect) { $TCPConnect = $True } } else { # port $Client = New-Object System.Net.Sockets.TcpClient $BeginConnect = $Client.BeginConnect($Work[0],$Work[1],$ReqCallback,$State) Start-Sleep -Millisecond $Timeout if ($True -eq $Client.Connected) { $TCPConnect = $True } $BeginConnect = $Client.Close } Write-Output ($TCPConnect) } -ArgumentList $IP,$Timeout } Do { Start-Sleep -Millisecond $Timeout } Until (@($joblist | Where-Object {$_.State -ne "Completed"}).count -eq 0) foreach ($Job in $JobList) { $Work = @($Job.Name.Split(":")) if ("" -eq ($Work[2]+"")) { $Result | Add-Member -MemberType NoteProperty -Name $Job.Name -Value (Receive-Job -Job $Job) if ($Result.($Job.Name) -eq $True) {$Result.($Job.Name)="o"} else {$Result.($Job.Name)="x"} } else { $Result | Add-Member -MemberType NoteProperty -Name $Work[2] -Value (Receive-Job -Job $Job) if ($Result.($Work[2]) -eq $True) {$Result.($Work[2])="o"} else {$Result.($Work[2])="x"} } } ## この辺で 件数に応じて情報整理する $Propname = Get-PropertyNames -Array $Result | Where-Object -FilterScript {$_ -ne "Count" -and $_ -ne "DateTime"} $Depth = [math]::Ceiling($Propname.Count / $Width) for ($j=0;$j -lt $Depth;$j++) { if ($True -eq $Datetime) { $Banner = $Result | Format-Table -AutoSize -Property (@("DateTime")+$Propname[($j*$Width)..($j*$Width+$Width-1)]) | Out-String -Stream } else { $Banner = $Result | Format-Table -AutoSize -Property (@("Count")+$Propname[($j*$Width)..($j*$Width+$Width-1)]) | Out-String -Stream } if (($i%$Height -eq 1) -or ($True -eq $EveryHeader)) { $Banner[0..2] } $Banner[3] } if ("" -ne $LogFile) { if ($True -eq $CSV) { if ($True -eq $isFirstTime) { ($Result | ConvertTo-CSV -NoTypeInformation)[0] | Out-file -FilePath $LogFile -Append:$Append -Encoding Default $isFirstTime = $False } ($Result | ConvertTo-CSV -NoTypeInformation)[1] | Out-file -FilePath $LogFile -Append -Encoding Default } else { $LongBanner = @() for ($j=0;$j -lt $Depth;$j++) { if (0 -eq $LongBanner.Count) { if ($True -eq $Datetime) { $Banner = $Result | Format-Table -AutoSize -Property (@("DateTime")+$Propname[($j*$Width)..($j*$Width+$Width-1)]) | Out-String -Stream } else { $Banner = $Result | Format-Table -AutoSize -Property (@("Count")+$Propname[($j*$Width)..($j*$Width+$Width-1)]) | Out-String -Stream } $LongBanner = $Banner } else { $Banner = $Result | Format-Table -AutoSize -Property ($Propname[($j*$Width)..($j*$Width+$Width-1)]) | Out-String -Stream for ($k=0;$k -lt $Banner.Count;$k++) { $LongBanner[$k] = $LongBanner[$k]+" "+$Banner[$k] } } } if ($True -eq $isFirstTime) { $LongBanner[1..2] | Out-file -FilePath $LogFile -Append:$Append -Encoding Default $isFirstTime = $False } $LongBanner[3] | Out-file -FilePath $LogFile -Append -Encoding Default } } $JobList | Remove-Job } } Finally { Write-Host ("Finally start"); $JobList | Remove-Job Get-Job | Remove-Job; Get-Job | Remove-Job; Get-Job | Remove-Job; Write-Host ("Removed JOB"); } } Export-ModuleMember -Function Get-PropertyNames, Get-MSProductLifeCycle, ConvertTo-Narrow, ConvertTo-Wide, Test-IsNumeric, Format-WindowsFeature, Compare-ObjectProperties, Test-QuickConnect, Test-MultiPing |