SHIMSOFT-iTunesSearch.psm1

function Get-iTunesAppInfo {
    <#
    .SYNOPSIS
    Apple App Store / Apple Mac App Store のアプリ情報を検索します。
 
    .DESCRIPTION
    Apple App Store / Apple Mac App Store のアプリ情報を検索します。
    MDM などでアプリの制御に利用する BundleID を比較的容易に確認できます。
 
 
    .EXAMPLE
    Get-iTunesAppInfo -Term Pages -Platform iPhone
 
    "Pages" を AppName に含む「iPhone」用アプリ情報を情報を列挙します。
 
    .EXAMPLE
    Get-iTunesAppInfo -Term Pages -Platform Mac
 
    "Pages" を AppName に含むの「Mac」用アプリ情報を情報を列挙します。
 
    .EXAMPLE
    Get-iTunesAppInfo -Term "Microsoft Word"
 
    "Microsoft Word" を AppName に含むの「iPhone」「iPad」用アプリ情報を情報を列挙します。
 
 
    .EXAMPLE
    Get-iTunesAppInfo -Term "Microsoft Word" -FilterMode Equal
 
    FilterMode オプションで Equal を指定すると Term に指定した文字列と一致する情報となるようにフィルターします。
 
 
    .EXAMPLE
    Get-iTunesAppInfo -Term 361285480 -AppID
 
    確認したいアプリの ID が判明している場合、Term オプションに ID を指定し、 -AppID オプションを指定することで
    アプリ情報を確認できます。
 
    .EXAMPLE
    Get-iTunesAppInfo -Term "361285480,361309726,361304891" -AppID
 
    確認したいアプリの ID が複数ある場合、カンマ区切りで文字列指定し、 -AppID オプションを指定することで
    一括でアプリ情報を確認できます。
 
 
    .EXAMPLE
    Get-iTunesAppInfo -Term apple -Developer
 
    "apple" を ArtistName に含むの「iPhone」「iPad」用アプリ情報を情報を列挙します。
 
 
    .EXAMPLE
    Get-iTunesAppInfo -Term com.apple.mobileme.fmf1 -BundleID
 
    "com.apple.mobileme.fmf1" という BundleID のアプリ情報を情報を列挙します。
 
 
    .EXAMPLE
    Get-iTunesAppInfo -Term "com.apple.mobileme.fmf1,com.apple.MobileAddressBook" -BundleID
 
    確認したいアプリの BundleID が複数ある場合、カンマ区切りで文字列指定し -BundleID オプションを指定することで
    一括でアプリ情報を確認できます。
 
 
    .PARAMETER Term
 
    検索するキーワードを指定します。スペースを含む場合は "Microsoft Word" の様にします。
 
    .PARAMETER Platform
 
    アプリの対象プラットフォームを指定します。
    iPhone : iPhone 用アプリ
    iPad : iPad 用アプリ
    Mac : Mac 用アプリ
    iPhone+iPad : iPhone / iPad 用アプリ混合
    All : iPhone / iPad / Mac 用アプリ混合
 
    デフォルト値は "iPhone+iPad"
 
    .PARAMETER Country
 
    AppSotre の国コードを指定します。デフォルト値は "jp" です。
 
    .PARAMETER AppID
 
    App の URL などから ID 情報が判明している場合、ID を指定して検索することができます。
 
 
    .PARAMETER Developer
 
    Term に指定したキーワードが開発者名である場合、このオプションを指定することでよりある程度フィルタして結果を出すことができます。
 
    .PARAMETER BundleID
 
    Term に指定したキーワードが BundleID ある場合、このオプションを指定することでよりある程度フィルタして結果を出すことができます。
 
 
    .PARAMETER FilterMode
 
    None, Equal, Like のいずれかを指定します。デフォルト値は Like です。
    検索結果が Term にどれほど近いかをフィルタする方式が変ります。
    FilterMode 未指定の時に、目的のものが見つからない場合は、None を指定してみてください。
    アプリ名が正確にわかっている場合は Equal を指定することでより発見しやすくなります。
 
 
    .LINK
 
    .NOTES
 
    .INPUTS
    パイプラインからの入力可能です。
 
    .OUTPUTS
    文字列
 
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Always multiple results.")]
    param(
        [Parameter(Mandatory=$True,Position=1)]
        [String]$Term,

        [Parameter(Mandatory=$false,Position=2)]
            [ValidateSet("iPhone","iPad","iPhone+iPad","Watch","Mac","AppleTV","All")]
        [String]$Platform="iPhone+iPad",

        [Parameter(Mandatory=$false,Position=3)]
        [String]$Country="jp",

        [Parameter(Mandatory=$false,Position=4)]
        [Switch]$AppID=$false,

        [Parameter(Mandatory=$false,Position=5)]
        [Switch]$Developer=$false,

        [Parameter(Mandatory=$false,Position=6)]
        [Switch]$BundleID=$false,

        [Parameter(Mandatory=$false,Position=7)]
            [ValidateSet("None","Like","Equal")]
        [String]$FilterMode="Like",

        [Parameter(Mandatory=$false,Position=8)]
        [Switch]$DeveloperID=$false

        )

    $iTunesSearchURL ="https://itunes.apple.com/search?"
    $iTunesLookupURL ="https://itunes.apple.com/lookup?"


    $WebClient = New-Object System.Net.WebClient
    $WebClient.Encoding = [System.Text.Encoding]::UTF8

Write-Verbose ("Term = '{0}', Platform = '{1}', Country = {2}, AppID : {3}, Developer : {4}, BundleID : {5}, Equal : {6}, DeviceID : {7}, Expand {8} " -f $Term, $Platform, $Country, $AppID,$Developer,$BundleID,$Equal,$DeviceID, $Expand)


    $is_iPhone = $false
    $is_iPad = $false
    $is_Mac = $false
    $is_Watch = $false
    $is_AppleTV = $false

    switch ($Platform) {
        "iPhone" {
            $is_iPhone = $true
        }

        "iPad" {
            $is_iPad = $true
        }
        "iPhone+iPad" {
            $is_iPhone = $true
            $is_iPad = $true
        }

        "Watch" {
            $is_Watch = $true
        }

        "Mac" {
            $is_Mac = $true
        }

        "AppleTV" {
            $is_AppleTV = $true
        }

        "All" {
            $is_iPhone = $true
            $is_iPad = $true
            $is_Mac = $true
            $is_Watch = $true
            $is_AppleTV = $true
        }

    }

    $AppInfo = @()

    $is_Finished = $false

    if ($AppId) {

Write-Verbose ("AppID mode")

        $URL = ('{0}id={1}&country={2}' -f $iTunesLookupURL, $Term, $Country)
        $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
        $Result = @($SearchResult.Results)
        if ($null -ne $Result) {
            $AppInfo += Summary-AppInfo -Results $Result
        }
        Write-Output ($AppInfo | Sort-Object -Property AppName)
        $is_Finished = $ttrue

    }


    if ($BundleId) {

Write-Verbose ("BundleID mode")

        $URL = ('{0}bundleId={1}&country={2}' -f $iTunesLookupURL, $Term, $Country)
        $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
        $Result = @($SearchResult.Results)
        if ($null -ne $Result) {
            $AppInfo += Summary-AppInfo -Results $Result
        }
        Write-Output ($AppInfo | Sort-Object -Property AppName)
        $is_Finished = $ttrue
    }

    if ($DeveloperId) {

Write-Verbose ("DeveloperID mode")

        $offset=0
        $Result = @()
        $All = $false

        While ($false -eq $All) {
            $URL = ('{0}id={1}&country={2}&entity=software&limit=200&offset={3}' -f $iTunesLookupURL, $Term, $Country, $offset)
            $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
            $Work = @($SearchResult.Results | Where-Object {$_.wrapperType -eq "software"})

            $Result  += $Work

            if ($Work.Count -ge 200) {$offset += 200;Write-Verbose ("`tOffset Loop:{0}" -f $offset); } else { $All = $true}
        }

        $AppInfo += Summary-AppInfo -Results $Result -ErrorAction SilentlyContinue

        $FilteredApps = @()
        if ($is_iPhone) { $FilteredApps += $AppInfo | Where-Object {$_.Platforms -eq "iPhone" } }
        if ($is_iPad)   { $FilteredApps += $AppInfo | Where-Object {$_.Platforms -eq "iPad" } }
        if ($is_Mac)    { $FilteredApps += $AppInfo | Where-Object {$_.Platforms -eq "Mac" } }
        if ($is_Watch)  { $FilteredApps += $AppInfo | Where-Object {$_.Platforms -eq "Watch" } }
        if ($is_AppleTV)  { $FilteredApps += $AppInfo | Where-Object {$_.Platforms -eq "AppleTV" } }

        $AppInfo = $FilteredApps | Sort-Object -Property AppID -Unique | Sort-Object -Property AppName

        Write-Output ($AppInfo)
        $is_Finished = $ttrue
    }

    $is_NoFiltered = $true


    if ($false -eq $is_Finished) {

Write-Verbose ("Normal mode")

        if ($Developer) {
            $FilterDeveloper=$Term

            $is_NoFiltered = $false
        }

        if ($is_iPhone) {

Write-Verbose ("iPhone mode")

            if ($Developer) {

                $URL = ('{0}term={1}&country={2}&entity=allArtist&attribute=softwareDeveloper&limit=200' -f $iTunesSearchURL, ($Term.Replace(" ","+")), $Country)
                $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
                $Result = @($SearchResult.Results | Where-Object {$_.artistType -eq "Software Artist"})

                switch ($FilterMode) {
                    "None"    {
                        $Result = $Result
                    }
                    "Equal" {
                        $Result = $Result | Where-Object {$_.artistName -eq ("{0}" -f $FilterDeveloper)}
                    }
                    "Like" {
                        $Result = $Result | Where-Object {$_.artistName -like ("*{0}*" -f $FilterDeveloper)}
                    }
                }

                foreach ($D in $Result.artistID) {
                    $AppInfo += Get-iTunesAppInfo -Term $D -Platform iPhone -DeveloperID -Country $Country -ErrorAction SilentlyContinue
                }

            } else {
                $Result = Search-iTunesStoreApp -Entity software -Term $Term -Country $Country
                if ($is_NoFiltered) {

                    switch ($FilterMode) {
                        "None"    {
                            $Result = $Result
                        }
                        "Equal" {
                            $Result = $Result | Where-Object {$_.trackName -eq ("{0}" -f $Term)}
                        }
                        "Like" {
                            $Result = $Result | Where-Object {$_.trackName -like ("*{0}*" -f $Term)}
                        }
                    }
                }

                if ($null -ne $Result) {
                    $AppInfo += Summary-AppInfo -Results $Result -ErrorAction SilentlyContinue
                }
            }

        }

        if ($is_iPad) {

Write-Verbose ("iPad mode")


            if ($Developer) {
                $URL = ('{0}term={1}&country={2}&entity=allArtist&attribute=softwareDeveloper&limit=200' -f $iTunesSearchURL, ($Term.Replace(" ","+")), $Country)
                $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
                $Result = @($SearchResult.Results | Where-Object {$_.artistType -eq "Software Artist"})

                switch ($FilterMode) {
                    "None"    {
                        $Result = $Result
                    }
                    "Equal" {
                        $Result = $Result | Where-Object {$_.artistName -eq ("{0}" -f $FilterDeveloper)}
                    }
                    "Like" {
                        $Result = $Result | Where-Object {$_.artistName -like ("*{0}*" -f $FilterDeveloper)}
                    }
                }

                foreach ($D in $Result.artistID) {
                    $AppInfo += Get-iTunesAppInfo -Term $D -Platform iPad -DeveloperID -Country $Country -ErrorAction SilentlyContinue
                }
            } else {
                $Result = Search-iTunesStoreApp -Entity iPadSoftware -Term $Term -Country $Country
                if ($is_NoFiltered) {
                    switch ($FilterMode) {
                        "None"    {
                            $Result = $Result
                        }
                        "Equal" {
                            $Result = $Result | Where-Object {$_.trackName -eq ("{0}" -f $Term)}
                        }
                        "Like" {
                            $Result = $Result | Where-Object {$_.trackName -like ("*{0}*" -f $Term)}
                        }
                    }
                }
                if ($null -ne $Result) {
                    $AppInfo += Summary-AppInfo -Results $Result -ErrorAction SilentlyContinue
                }
            }
        }

        if ($is_Mac) {

Write-Verbose ("Mac mode")


            if ($Developer) {
                $URL = ('{0}term={1}&country={2}&entity=allArtist&attribute=softwareDeveloper&limit=200' -f $iTunesSearchURL, ($Term.Replace(" ","+")), $Country)
                $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
                $Result = @($SearchResult.Results | Where-Object {$_.artistType -eq "Software Artist"})

                switch ($FilterMode) {
                    "None"    {
                        $Result = $Result
                    }
                    "Equal" {
                        $Result = $Result | Where-Object {$_.artistName -eq ("{0}" -f $FilterDeveloper)}
                    }
                    "Like" {
                        $Result = $Result | Where-Object {$_.artistName -like ("*{0}*" -f $FilterDeveloper)}
                    }
                }

                foreach ($D in $Result.artistID) {
                    $AppInfo += Get-iTunesAppInfo -Term $D -Platform Mac -DeveloperID -Country $Country -ErrorAction SilentlyContinue
                }
            } else {
                $Result = Search-iTunesStoreApp -Entity macSoftware -Term $Term -Country $Country
                if ($is_NoFiltered) {
                    switch ($FilterMode) {
                        "None"    {
                            $Result = $Result
                        }
                        "Equal" {
                            $Result = $Result | Where-Object {$_.trackName -eq ("{0}" -f $Term)}
                        }
                        "Like" {
                            $Result = $Result | Where-Object {$_.trackName -like ("*{0}*" -f $Term)}
                        }
                    }
                }

                if ($null -ne $Result) {
                    $AppInfo += Summary-AppInfo -Results $Result -ErrorAction SilentlyContinue
                }
            }
        }

        if ($is_Watch) {

Write-Verbose ("Watch mode")


            if ($Developer) {
                $URL = ('{0}term={1}&country={2}&entity=allArtist&attribute=softwareDeveloper&limit=200' -f $iTunesSearchURL, ($Term.Replace(" ","+")), $Country)
                $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
                $Result = @($SearchResult.Results | Where-Object {$_.artistType -eq "Software Artist"})

                switch ($FilterMode) {
                    "None"    {
                        $Result = $Result
                    }
                    "Equal" {
                        $Result = $Result | Where-Object {$_.artistName -eq ("{0}" -f $FilterDeveloper)}
                    }
                    "Like" {
                        $Result = $Result | Where-Object {$_.artistName -like ("*{0}*" -f $FilterDeveloper)}
                    }
                }

                foreach ($D in $Result.artistID) {
                    $AppInfo += Get-iTunesAppInfo -Term $D -Platform Watch -DeveloperID -Country $Country -ErrorAction SilentlyContinue
                }

            } else {
                $Result = Search-iTunesStoreApp -Entity watchSoftware -Term $Term -Country $Country
                if ($is_NoFiltered) {
                    switch ($FilterMode) {
                        "None"    {
                            $Result = $Result
                        }
                        "Equal" {
                            $Result = $Result | Where-Object {$_.trackName -eq ("{0}" -f $Term)}
                        }
                        "Like" {
                            $Result = $Result | Where-Object {$_.trackName -like ("*{0}*" -f $Term)}
                        }
                    }
                }

                if ($null -ne $Result) {
                    $AppInfo += Summary-AppInfo -Results $Result -ErrorAction SilentlyContinue
                }
            }
        }

        if ($is_AppleTV) {

Write-Verbose ("AppleTV mode")


            if ($Developer) {
                $URL = ('{0}term={1}&country={2}&entity=allArtist&attribute=softwareDeveloper&limit=200' -f $iTunesSearchURL, ($Term.Replace(" ","+")), $Country)
                $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
                $Result = @($SearchResult.Results | Where-Object {$_.artistType -eq "Software Artist"})

                switch ($FilterMode) {
                    "None"    {
                        $Result = $Result
                    }
                    "Equal" {
                        $Result = $Result | Where-Object {$_.artistName -eq ("{0}" -f $FilterDeveloper)}
                    }
                    "Like" {
                        $Result = $Result | Where-Object {$_.artistName -like ("*{0}*" -f $FilterDeveloper)}
                    }
                }
                foreach ($D in $Result.artistID) {
                    $AppInfo += Get-iTunesAppInfo -Term $D -Platform Watch -DeveloperID -Country $Country -ErrorAction SilentlyContinue
                }
            } else {
                $Result = Search-iTunesStoreApp -Entity tvSoftware -Term $Term -Country $Country
                if ($is_NoFiltered) {
                    switch ($FilterMode) {
                        "None"    {
                            $Result = $Result
                        }
                        "Equal" {
                            $Result = $Result | Where-Object {$_.trackName -eq ("{0}" -f $Term)}
                        }
                        "Like" {
                            $Result = $Result | Where-Object {$_.trackName -like ("*{0}*" -f $Term)}
                        }
                    }
                }

                if ($null -ne $Result) {
                    $AppInfo += Summary-AppInfo -Results $Result -ErrorAction SilentlyContinue
                }
            }
        }



        $AppInfo = $AppInfo | Sort-Object -Property AppID -Unique | Where-Object -Property AppName
        Write-Output ($AppInfo)
    }
}


function Search-iTunesStoreApp {
    param(
        [Parameter(Mandatory=$false,Position=1)]
            [ValidateSet("software","iPadSoftware","macSoftware","watchSoftware","tvSoftware")]
        [String]$Entity="software",

        [Parameter(Mandatory=$true,Position=2)]
        [String]$Term,

        [Parameter(Mandatory=$false,Position=3)]
        [String]$Country="jp"

    )

    $iTunesSearchURL ="https://itunes.apple.com/search?"

    $WebClient = New-Object System.Net.WebClient
    $WebClient.Encoding = [System.Text.Encoding]::UTF8

    $offset=0
    $Result = @()
    $All = $false

    While ($false -eq $All) {

        $URL = ('{0}term={1}&country={2}&entity={3}&limit=200&offset={4}' -f $iTunesSearchURL, ($Term.Replace(" ","+")), $Country,$Entity,$offset)

        $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
        $Work = @($SearchResult.Results)
        $Result += $Work

        if ($Work.Count -ge 200) {$offset += 200;Write-Verbose ("`tOffset Loop:{0}" -f $offset); } else { $All = $true}
    }


    $Result = $Result | Sort-Object -Property TrackID -Unique

    Write-Output @($Result)

}



function Summary-AppInfo {
    param(
        [Parameter(Mandatory=$true,Position=1)]
        [Array]$Results
        )

    $AppInfo = @()

    foreach ($R in $Results) {
        $Mem = New-Object PSObject
        $Mem | Add-Member -MemberType NoteProperty -Name AppName -Value $R.trackName
        $Mem | Add-Member -MemberType NoteProperty -Name Version -Value $R.version
        $Mem | Add-Member -MemberType NoteProperty -Name AppID -Value $R.trackID
        $Mem | Add-Member -MemberType NoteProperty -Name BundleID -Value $R.bundleID
        $Mem | Add-Member -MemberType NoteProperty -Name ArtistName -Value $R.artistName
        $Mem | Add-Member -MemberType NoteProperty -Name SellerName -Value $R.sellerName

        $Mem | Add-Member -MemberType NoteProperty -Name Description -Value $R

        $Platforms = @()

        $Work = @($R.SupportedDevices | Where-Object { $_ -like "iPhone*"})
        if ($Work.Count -ne 0) { $Platforms += "iPhone" }

        $Work = @($R.SupportedDevices | Where-Object { $_ -like "iPad*"})
        if ($Work.Count -ne 0) { $Platforms += "iPad" }

        $Work = @($R.SupportedDevices | Where-Object { $_ -like "Mac*"})
        if ($Work.Count -ne 0) { $Platforms += "Mac" }

        if ($R.kind -eq "mac-software") { $Platforms += "Mac" }

        $Work = @($R.SupportedDevices | Where-Object { $_ -like "Watch*"})
        if ($Work.Count -ne 0) { $Platforms += "Watch" }

        $Work = @($R.SupportedDevices | Where-Object { $_ -like "AppleTV*"})
        if ($Work.Count -ne 0) { $Platforms += "AppleTV" }

        $Platforms = @($Platforms | Sort-Object -Unique)

        $Mem | Add-Member -MemberType NoteProperty -Name Platforms -Value $Platforms

        $defaultProperties = @("AppName","AppID","BundleID","ArtistName")

        $defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet("DefaultDisplayPropertySet",[string[]]$defaultProperties)
        $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
        $Mem | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers

        $AppInfo += $Mem
    }
    Write-Output $AppInfo
}

#
# Get-iTunesArtistInfo
#

function Get-iTunesArtistInfo {
    <#
    .SYNOPSIS
    iTunes Store の Artist 情報を検索します。
 
    .DESCRIPTION
    iTunes Store の Artist 情報を検索します。
 
 
    .EXAMPLE
    Get-iTunesArtistInfo -Term 広島綾子
    アーティスト名で検索する場合
 
    .EXAMPLE
    Get-iTunesArtistInfo -Teem "広島*綾子"
    アーティスト名の姓名のは間に半角スペースの有無など不明な場合、ワイルドカードの "*" を指定します。
 
    .EXAMPLE
    Get-iTunesArtistInfo -Term Apple -ArtistType SoftwareArtist -FilterMode Equal
 
    "Apple" というソフトウェア開発者を探す場合。
    Term に "Apple" と指定し、ArtistType オプションで "SoftwareArtist" を指定して種別を限定します。
    且つ、FilterMode オプションに "Equal" を指定し、Term と同じ文字列を持つものだけにフィルタします。
 
    Term に "Apple" のみの場合、"Apple" を ArtistName に含むすべてのアーティストが検索結果に含まれ、
    名前が "Apple Bank" など "Apple" ではないものや音楽系のアーティストも含まれてしまいます。
 
 
    .PARAMETER Term
 
    検索するキーワードを指定します。スペースを含む場合は "TM Network" の様にします。
 
    .PARAMETER Search
    検索するあ0ティスとカテゴリを指定します。
    musicArtist、movieArtist、shorFilmArtist、allArtist から選択します。
    ソフトウェア開発者を検索したい場合は AllArtist を指定してください。
    デフォルト値は "allArtist" です。
    App 開発元を検索したい場合は "allArtist" を指定してください。
    それによって「Software Artist」種別がヒットするようになります。
 
    .PARAMETER ArtistType
    結果リストとして必要とするアーティスト種別を指定します。
    を指定します。
    All、Artist、SoftwareArtist、PodcastArtist、MovieArtist から選択します。
    デフォルト値は AllArtist です。
 
 
    .PARAMETER Country
 
    AppSotre の国コードを指定します。デフォルト値は "jp" です。
 
    .PARAMETER ArtiestID
 
    Artist の URL などから ID 情報が判明している場合、ID を指定して検索することができます。
 
 
    .PARAMETER FilterMode
 
    Term に指定したキーワードが ArtistName に含まれる度合いを指定します。
    None、Like、Equal から指定します。
    規定値は "Like" です。
 
    "None" を指定した場合、iTunes 検索結果のリストをそのまま出力として使用します。
    ArtistName に指定した Term が直接的に含まれていないものが結果に含まれる可能性があります。
 
    "Like" を指定した場合、iTunes 検索検索結果の ArtistName に Term 文字列が含まれるもののみをフィルタして返します。
    意図した検索結果が見つかりやすくなります。
 
    "Equal" を指定した場合、iTunes 検索結果のリストから ArtistName が Term 文字列と同じもののみをフィルタして返します。
    検索対象のフルネームなどを知っている場合に検索結果を見つけやすくなる場合があります。
 
 
    .LINK
 
    .NOTES
 
    .INPUTS
    パイプラインからの入力可能です。
 
    .OUTPUTS
    文字列
 
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Always multiple results.")]
    param(
        [Parameter(Mandatory=$True,Position=1)]
        [String]$Term,

        [Parameter(Mandatory=$false,Position=2)]
            [ValidateSet("mixTerm","genreIndex","artistTerm","composerTerm","albumTerm","raitingIndex","songTerm","producerTerm")]
        [String]$TermType="mixTerm",

        [Parameter(Mandatory=$false,Position=3)]
            [ValidateSet("movieArtist","musicArtist","shortFilmArtist","allArtist")]
        [String]$Search="allArtist",

        [Parameter(Mandatory=$false,Position=4)]
            [ValidateSet("All","Artist","SoftwareArtist","PodcastArtist","MovieArtist")]
        [String]$ArtistType="All",

        [Parameter(Mandatory=$false,Position=5)]
        [String]$Country="jp",

        [Parameter(Mandatory=$false,Position=6)]
        [Switch]$ArtistID=$false,

        [Parameter(Mandatory=$false,Position=7)]
            [ValidateSet("None","Like","Equal")]
        [String]$FilterMode="None"



        )

    $iTunesSearchURL ="https://itunes.apple.com/search?"
    $iTunesLookupURL ="https://itunes.apple.com/lookup?"


    $WebClient = New-Object System.Net.WebClient
    $WebClient.Encoding = [System.Text.Encoding]::UTF8

Write-Verbose ("Term = '{0}', Search = {1}, ArtistType = {2}, Country = {3}, ArtistID : {4}, FilterMode : {4}, TermType : {5}" -f $Term, $Search, $ArtistType, $Country, $ArtistID, $FilterMode, $TermType)


    $ArtistInfo = @()

    if ($ArtistId) {
        $URL = ('{0}id={1}&country={2}' -f $iTunesLookupURL, $Term, $Country)
        $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
        $Result = @($SearchResult.Results)
        if ($null -ne $Result) {
            $ArtistInfo += Summary-ArtistInfo -Results $Result
        }
    } else {
        $URL = ('{0}term={1}&country={2}&entity={3}&limit=200&attribute={4}' -f $iTunesSearchURL, ($Term.Replace(" ","+")), $Country, $Search,$TermType)

        $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
        $Result = @($SearchResult.Results)


        switch ($ArtistType) {
            "All"    {
                $Result = $Result
            }

            "Artist" {
                $Result = $Result | Where-Object {$_.artistType -eq "Artist"}
            }
            "SoftwareArtist" {
                $Result = $Result | Where-Object {$_.artistType -eq "Software Artist"}
            }
            "PodcastArtist" {
                $Result = $Result | Where-Object {$_.artistType -eq "Podcast Artist"}
            }
            "MovieArtist" {
                $Result = $Result | Where-Object {$_.artistType -eq "Movie Artist"}
            }

        }

        switch ($FilterMode) {
            "None"    {
                $Result = $Result
            }

            "Like" {
                $Result = $Result | Where-Object {$_.artistName -like ("*{0}*" -f $Term)}
            }
            "Equal" {
                $Result = $Result | Where-Object {$_.artistName -eq ("{0}" -f $Term)}
            }
        }

        if ($null -ne $Result) {
            $ArtistInfo += Summary-ArtistInfo -Results $Result
        }
    }


    $ArtistInfo = $ArtistInfo | Sort-Object -Property ArtistName
    Write-Output ($ArtistInfo)

}

function Summary-ArtistInfo {
    param(
        [Parameter(Mandatory=$true,Position=1)]
        [Array]$Results
        )

    $ArtistInfo = @()

    foreach ($R in $Results) {
        $Mem = New-Object PSObject
        $Mem | Add-Member -MemberType NoteProperty -Name ArtistName -Value $R.ArtistName
        $Mem | Add-Member -MemberType NoteProperty -Name ArtistType -Value $R.ArtistType
        $Mem | Add-Member -MemberType NoteProperty -Name ArtistID -Value $R.ArtistID
        $Mem | Add-Member -MemberType NoteProperty -Name PrimaryGenreName -Value $R.PrimaryGenreName
        $Mem | Add-Member -MemberType NoteProperty -Name LinkURL -Value $R.ArtistLinkUrl

        $Mem | Add-Member -MemberType NoteProperty -Name Description -Value $R


        $defaultProperties = @("ArtistName","ArtistType","ArtistID","PrimaryGenreName")

        $defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet("DefaultDisplayPropertySet",[string[]]$defaultProperties)
        $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
        $Mem | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers

        $ArtistInfo += $Mem
    }
    Write-Output $ArtistInfo
}





#
# Get-iTunesMusicInfo
#

function Get-iTunesMusicInfo {
    <#
    .SYNOPSIS
    iTunes Store の楽曲情報を検索します。
 
    .DESCRIPTION
    iTunes Store の楽曲情報を検索します。
 
 
    .EXAMPLE
    Get-iTunesMusicInfo -Term 広島綾子 -Artist -WhatIs Album
 
    アーティスト「広島綾子」のアルバムを表示します。
 
 
    .PARAMETER Term
 
    検索するキーワードを指定します。スペースを含む場合は "Microsoft Word" の様にします。
 
    .PARAMETER TermType
 
    検索キーワードの種類を指定します。
 
    mixTerm = デフォルト値。複合。
    genreIndex = ジャンルを指定
    artistTerm = アーティスト名を指定
    composerTerm = コンポーザーを指定
    albumTerm = アルバムを指定
    raitingIndex = レートを指定
    songTerm = 曲名を指定
    producerTerm = プロデューサーを指定
 
    .PARAMETER WhatIs
 
    検索対象を指定します。
    musicTrack = musicTrack が対象になります。
    album = アルバムが対象になります。
    musicVideo = ミュージックビデオ が対象になります。
    mix = 複合。
    song = デフォルト値。歌が対象になります。
 
 
    .PARAMETER Country
 
    AppSotre の国コードを指定します。デフォルト値は "jp" です。
 
    .PARAMETER SongID
 
    楽曲の URL などから ID 情報が判明している場合、ID を指定して検索することができます。
 
    .PARAMETER AlbumID
 
    アルバムの URL などから ID 情報が判明している場合、ID を指定して検索することができます。
 
 
    .PARAMETER Artist
 
    Term に指定したキーワードがアーティスト名である場合、このオプションを指定することでよりある程度フィルタして結果を出すことができます。
 
    .PARAMETER ArtistID
 
    アーティストの URL などから ID 情報が判明している場合、ID を指定して検索することができます。
 
 
    .PARAMETER FilterMode
 
    Term に指定したキーワードが ArtistName に含まれる度合いを指定します。
    None、Like、Equal から指定します。
    規定値は "None" です。
 
    "None" を指定した場合、iTunes 検索結果のリストをそのまま出力として使用します。
    ArtistName に指定した Term が直接的に含まれていないものが結果に含まれる可能性があります。
 
    "Like" を指定した場合、iTunes 検索検索結果に Term 文字列が含まれるもののみをフィルタして返します。
    意図した検索結果が見つかりやすくなります。
 
    "Equal" を指定した場合、iTunes 検索結果のリストから Term 文字列と同じもののみをフィルタして返します。
    検索対象の登録名称などを知っている場合に検索結果を見つけやすくなる場合があります。
 
 
    .LINK
 
    .NOTES
 
    .INPUTS
    パイプラインからの入力可能です。
 
    .OUTPUTS
    文字列
 
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "", Justification="Always multiple results.")]
    param(
        [Parameter(Mandatory=$True,Position=1)]
        [String]$Term,

        [Parameter(Mandatory=$false,Position=2)]
            [ValidateSet("mixTerm","genreIndex","artistTerm","composerTerm","albumTerm","raitingIndex","songTerm","producerTerm")]
        [String]$TermType="mixTerm",

        [Parameter(Mandatory=$false,Position=3)]
            [ValidateSet("musicTrack","album","musicVideo","mix","song")]
        [String]$WhatIs="song",

        [Parameter(Mandatory=$false,Position=4)]
        [String]$Country="jp",

        [Parameter(Mandatory=$false,Position=5)]
        [Switch]$SongID=$false,

        [Parameter(Mandatory=$false,Position=6)]
        [Switch]$AlbumID=$false,

        [Parameter(Mandatory=$false,Position=7)]
        [Switch]$Artist=$false,

        [Parameter(Mandatory=$false,Position=8)]
        [Switch]$ArtistID=$false,

        [Parameter(Mandatory=$false,Position=9)]
            [ValidateSet("None","Like","Equal")]
        [String]$FilterMode="None"

        )

    $iTunesSearchURL ="https://itunes.apple.com/search?"
    $iTunesLookupURL ="https://itunes.apple.com/lookup?"


    $WebClient = New-Object System.Net.WebClient
    $WebClient.Encoding = [System.Text.Encoding]::UTF8

Write-Verbose ("Term = '{0}', TermType = '{1}', WhatIs = {2}, Country = {3}, SongID : {4}, AlbumID : {5}, Artist : {6}, ArtistID : {7}, FilterMode : {8}" -f $Term, $TermType, $WhatIs, $Country, $SongID, $AlbumID, $Artist, $ArtistID, $FilterMode)

    $MusicInfo = @()

    $is_Finished = $false

    if ($SongID) {
        $URL = ('{0}id={1}&country={2}' -f $iTunesLookupURL, $Term, $Country)
        $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
        $Result = @($SearchResult.Results)
        if ($null -ne $Result) {
            $MusicInfo += Summary-MusicInfo -Results $Result
        }
        $is_Finished = $True
    }


    if ($AlbumId) {

        $offset=0
        $Result = @()
        $All = $false

        While ($false -eq $All) {

            $URL = ('{0}id={1}&country={2}&offset={3}&entity={4}&limit=200' -f $iTunesLookupURL, $Term, $Country,$offset,$WhatIs)
            $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
            $Work = @($SearchResult.Results)
            $Result += $Work

            if ($Work.Count -ge 200) {$offset += 200;Write-Verbose ("`tOffset Loop:{0}" -f $offset); } else { $All = $true}
        }
        if ($null -ne $Result) {
            $MusicInfo += Summary-MusicInfo -Results $Result
        }
        $is_Finished = $True
    }


    if ($ArtistId) {

Write-Verbose ("ArtistID")

        $offset=0
        $Result = @()
        $All = $false

        While ($false -eq $All) {

            $URL = ('{0}id={1}&country={2}&limit=200&offset={3}&entity={4}' -f $iTunesLookupURL, $Term, $Country,$offset,$WhatIs)
            $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
            $Work = @($SearchResult.Results)
            $Result += $Work

            if ($Work.Count -ge 200) {$offset += 200;Write-Verbose ("`tOffset Loop:{0}" -f $offset); } else { $All = $true}
            $All = $true
        }
        if ($null -ne $Result) {
            $MusicInfo += Summary-MusicInfo -Results $Result
        }
        $is_Finished = $True
    }


    if ($false -eq $is_Finished) {

        if ($Artist) {
            $FilterArtist=$Term

        }

        if ($Artist) {

            $URL = ('{0}term={1}&country={2}&entity=musicArtist&attribute=artistTerm&limit=200' -f $iTunesSearchURL, ($Term.Replace(" ","+")), $Country)
            $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
            $Result = @($SearchResult.Results | Where-Object {$_.artistType -ne "Software Artist"})

            switch ($FilterMode) {
                "None"    {
                    $Result = $Result
                }
                "Equal" {
                    $Result = $Result | Where-Object {$_.artistName -eq ("{0}" -f $FilterArtist)}
                }
                "Like" {
                    $Result = $Result | Where-Object {$_.artistName -like ("*{0}*" -f $FilterArtist)}
                }
            }

            foreach ($A in $Result.artistID) {
                $MusicInfo += Get-iTunesMusicInfo -Term $A -WhatIs $WhatIs -ArtistID -Country $Country -ErrorAction SilentlyContinue
            }

        } else {

            $offset=0
            $Result = @()
            $All = $false

            While ($false -eq $All) {

                $URL = ('{0}term={1}&country={2}&entity={3}&attribute={4}&limit=200&offset={5}' -f $iTunesSearchURL, ($Term.Replace(" ","+")), $Country, $WhatIs, $TermType,$offset)

                $SearchResult = ConvertFrom-Json $WebClient.DownloadString($URL)
                $Work = @($SearchResult.Results)
                $Result += $Work

                if ($Work.Count -ge 200) {$offset += 200;Write-Verbose ("`tOffset Loop:{0}" -f $offset); } else { $All = $true}
            }

            switch ($FilterMode) {
                "None" {
                    $Result = $Result
                }

                "Like" {
                    switch ($TermType) {

                        "producerTerm"    {
                            $Result = $Result | Where-Object {$_.artistName -like ("*{0}*" -f $Term)}
                        }
                        "composerTerm"    {
                            $Result = $Result | Where-Object {$_.artistName -like ("*{0}*" -f $Term)}
                        }

                        "artistTerm"    {
                            $Result = $Result | Where-Object {$_.artistName -like ("*{0}*" -f $Term)}
                        }

                        "genreIndex"    {
                            $Result = $Result | Where-Object {$_.primaryGenreName -like ("*{0}*" -f $Term)}
                        }

                        "albumTerm"    {
                            $Result = $Result | Where-Object {$_.collectionName -like ("*{0}*" -f $Term)}
                        }

                        default    {
                            $Result = $Result | Where-Object {$_.trackName -like ("*{0}*" -f $Term)}
                        }
                    }
                }

                "Equal" {
                    switch ($TermType) {
                        "producerTerm"    {
                            $Result = $Result | Where-Object {$_.artistName -eq ("{0}" -f $Term)}
                        }
                        "composerTerm"    {
                            $Result = $Result | Where-Object {$_.artistName -eq ("{0}" -f $Term)}
                        }

                        "artistTerm"    {
                            $Result = $Result | Where-Object {$_.artistName -eq ("{0}" -f $Term)}
                        }

                        "genreIndex"    {
                            $Result = $Result | Where-Object {$_.primaryGenreName -eq ("{0}" -f $Term)}
                        }

                        "albumTerm"    {
                            $Result = $Result | Where-Object {$_.collectionName -eq ("{0}" -f $Term)}
                        }

                        default {
                            $Result = $Result | Where-Object {$_.trackName -eq ("{0}" -f $Term)}
                        }
                    }
                }
            }


            if ($null -ne $Result) {
                $MusicInfo += Summary-MusicInfo -Results $Result
            }


        }

    }

    switch ($WhatIs) {
        "album" {
            $MusicInfo = $MusicInfo | Where-Object {$_.Description.wrapperType -ne "artist" } | Sort-Object -Property AlbumID -Unique | Sort-Object -Property ArtistName,AlbumName,Disc-Track,MusicName
        }

        default {
            $MusicInfo = $MusicInfo | Where-Object {$_.Description.wrapperType -ne "artist" } | Sort-Object -Property MusicID -Unique | Sort-Object -Property ArtistName,AlbumName,Disc-Track,MusicName
        }
    }
    Write-Output ($MusicInfo)

}


function Summary-MusicInfo {
    param(
        [Parameter(Mandatory=$true,Position=1)]
        [Array]$Results
        )

    $MusicInfo = @()

    foreach ($R in $Results) {

        switch ($R.wrapperType) {
            "collection" {
                $Mem = New-Object PSObject

                $Mem | Add-Member -MemberType NoteProperty -Name AlbumName -Value $R.collectionName
                $Mem | Add-Member -MemberType NoteProperty -Name AlbumID -Value $R.collectionID
                $Mem | Add-Member -MemberType NoteProperty -Name AlbumURL -Value $R.collectionViewURL

                $Mem | Add-Member -MemberType NoteProperty -Name ArtistName -Value $R.artistName
                $Mem | Add-Member -MemberType NoteProperty -Name ArtistID -Value $R.ArtistID
                $Mem | Add-Member -MemberType NoteProperty -Name ArtistURL -Value $R.artistViewURL

                $Mem | Add-Member -MemberType NoteProperty -Name Tracks -Value  $this.TrackCount

                $Mem | Add-Member -MemberType NoteProperty -Name ReleaseDate -Value $R.releaseDate

                $Mem | Add-Member -MemberType NoteProperty -Name Description -Value $R

                $defaultProperties = @("AlbumName","ArtistName","Tracks","ReleaseDate")

                $defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet("DefaultDisplayPropertySet",[string[]]$defaultProperties)
                $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
                $Mem | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers
            }

            default {
                $Mem = New-Object PSObject
                $Mem | Add-Member -MemberType NoteProperty -Name MusicName -Value $R.trackName
                $Mem | Add-Member -MemberType NoteProperty -Name MusicID -Value $R.trackID
                $Mem | Add-Member -MemberType NoteProperty -Name MusicURL -Value $R.trackViewURL

                $Mem | Add-Member -MemberType NoteProperty -Name AlbumName -Value $R.collectionName
                $Mem | Add-Member -MemberType NoteProperty -Name AlbumID -Value $R.collectionID
                $Mem | Add-Member -MemberType NoteProperty -Name AlbumURL -Value $R.collectionViewURL

                $Mem | Add-Member -MemberType NoteProperty -Name ArtistName -Value $R.artistName
                $Mem | Add-Member -MemberType NoteProperty -Name ArtistID -Value $R.ArtistID
                $Mem | Add-Member -MemberType NoteProperty -Name ArtistURL -Value $R.artistViewURL

                $Mem | Add-Member -MemberType NoteProperty -Name DiscCount -Value $R.DiscCount
                $Mem | Add-Member -MemberType NoteProperty -Name DiscNumber -Value $R.DiscNumber
                $Mem | Add-Member -MemberType NoteProperty -Name TrackCount -Value $R.TrackCount
                $Mem | Add-Member -MemberType NoteProperty -Name TrackNumber -Value $R.TrackNumber
                $Mem | Add-Member -MemberType ScriptProperty -Name Disc-Track -Value { ("{0:00}/{1:00}-{2:00}/{3:00}" -f $this.DiscNumber, $this.DiscCount, $this.TrackNumber, $this.TrackCount) }

                $Mem | Add-Member -MemberType NoteProperty -Name ReleaseDate -Value $R.releaseDate

                $Mem | Add-Member -MemberType NoteProperty -Name Description -Value $R

                $defaultProperties = @("Disc-Track","AlbumName","MusicName","ArtistName")

                $defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet("DefaultDisplayPropertySet",[string[]]$defaultProperties)
                $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
                $Mem | Add-Member -MemberType MemberSet -Name PSStandardMembers -Value $PSStandardMembers
            }
        }

        $MusicInfo += $Mem
    }
    Write-Output $MusicInfo
}




Export-ModuleMember -Function Get-iTunesAppInfo, Get-itunesArtistInfo, Get-iTunesMusicInfo