pwshPlaces.psm1
# This is a locally sourced Imports file for local development. # It can be imported by the psm1 in local development to add script level variables. # It will merged in the build process. This is for local development only. #region script variables # $script:resourcePath = "$PSScriptRoot\Resources" $script:googleMapsBaseURI = 'https://maps.googleapis.com/maps/api/' $script:bingMapsBaseURI = 'https://dev.virtualearth.net/REST/' #endregion #region parameter enums enum ccTLD { ac #Ascension Island ad #Andorra ae #United Arab Emirate af #Afghanistan ag #Antigua and Barbuda ai #Anguilla al #Albania am #Armenia ao #Angola aq #Antarctica ar #Argentina as #American Samoa at #Austria au #Australia aw #Aruba ax #Åland Islands az #Azerbaijan ba #Bosnia and Herzegov bb #Barbados bd #Bangladesh be #Belgium bf #Burkina Faso bg #Bulgaria bh #Bahrain bi #Burundi bj #Benin bm #Bermuda bn #Brunei bo #Bolivia br #Brazil bs #Bahamas bt #Bhutan bv #Bouvet Island bw #Botswana by #Belarus bz #Belize ca #Canada cc #Cocos (Keeling) Isl cd #Democratic Republic cf #Central African Rep cg #Republic of the Con ch #Switzerland ci #Ivory Coast ck #Cook Islands cl #Chile cm #Cameroon cn #China co #Colombia cr #Costa Rica cu #Cuba cv #Cape Verde cw #Curaçao cx #Christmas Island cy #Cyprus cz #Czech Republic de #Germany dj #Djibouti dk #Denmark dm #Dominica do #Dominican Republic dz #Algeria ec #Ecuador ee #Estonia eg #Egypt er #Eritrea es #Spain et #Ethiopia eu #European Union fi #Finland fj #Fiji fk #Falkland Islands fm #Micronesia fo #Faroe Islands fr #France ga #Gabon gb #United Kingdom gd #Grenada ge #Georgia gf #French Guiana gg #Guernsey gh #Ghana gi #Gibraltar gl #Greenland gm #Gambia gn #Guinea gp #Guadeloupe gq #Equatorial Guinea gr #Greece gs #South Georgia gt #Guatemala gu #Guam gw #Guinea-Bissau gy #Guyana hk #Hong Kong hm #Heard Island and Mc hn #Honduras hr #Croatia ht #Haiti hu #Hungary id #Indonesia ie #Ireland il #Israel im #Isle of Man in #India io #British Indian Ocea iq #Iraq ir #Iran is #Iceland it #Italy je #Jersey jm #Jamaica jo #Jordan jp #Japan ke #Kenya kg #Kyrgyzstan kh #Cambodia ki #Kiribati km #Comoros kn #Saint Kitts and Nev kp #North Korea kr #South Korea kw #Kuwait ky #Cayman Islands kz #Kazakhstan la #Laos lb #Lebanon lc #Saint Lucia li #Liechtenstein lk #Sri Lanka lr #Liberia ls #Lesotho lt #Lithuania lu #Luxembourg lv #Latvia ly #Libya ma #Morocco mc #Monaco md #Moldova me #Montenegro mg #Madagascar mh #Marshall Islands mk #North Macedonia ml #Mali mm #Myanmar mn #Mongolia mo #Macao mp #Northern Mariana Is mq #Martinique mr #Mauritania ms #Montserrat mt #Malta mu #Mauritius mv #Maldives mw #Malawi mx #Mexico my #Malaysia mz #Mozambique na #Namibia nc #New Caledonia ne #Niger nf #Norfolk Island ng #Nigeria ni #Nicaragua nl #Netherlands no #Norway np #Nepal nr #Nauru nu #Niue nz #New Zealand om #Oman pa #Panama pe #Peru pf #French Polynesia pg #Papua New Guinea ph #Philippines pk #Pakistan pl #Poland pm #Saint Pierre and Mi pn #Pitcairn Islands pr #Puerto Rico ps #Palestine pt #Portugal pw #Palau py #Paraguay qa #Qatar re #Réunion ro #Romania rs #Serbia ru #Russia rw #Rwanda sa #Saudi Arabia sb #Solomon Islands sc #Seychelles sd #Sudan se #Sweden sg #Singapore sh #Saint Helena si #Slovenia sj #Svalbard and Jan Ma sk #Slovakia sl #Sierra Leone sm #San Marino sn #Senegal so #Somalia sr #Suriname ss #South Sudan st #Sao Tome and Princi su #Soviet Union sv #El Salvador sx #Sint Maarten sy #Syria sz #Eswatini tc #Turks and Caicos Is td #Chad tf #French Southern Ter tg #Togo th #Thailand tj #Tajikistan tk #Tokelau tl #East Timor tm #Turkmenistan tn #Tunisia to #Tonga tr #Turkey tt #Trinidad and Tobago tv #Tuvalu tw #Taiwan tz #Tanzania ua #Ukraine ug #Uganda uk #United Kingdom us #United States uy #Uruguay uz #Uzbekistan va #Vatican vc #Saint Vincent and t ve #Venezuela vg #British Virgin Isla vi #U.S. Virgin Islands vn #Vietnam vu #Vanuatu wf #Wallis and Futuna ws #Samoa ye #Yemen yt #Mayotte za #South Africa zm #Zambia zw #Zimbabwe } #enum_ccTLD #region GMaps enums # https://developers.google.com/maps/faq#languagesupport enum languages { af #Afrikaans sq #Albanian am #Amharic ar #Arabic hy #Armenian az #Azerbaijani eu #Basque be #Belarusian bn #Bengali bs #Bosnian bg #Bulgarian my #Burmese ca #Catalan zh #Chinese # zh-CN #Chinese (Simplified) # zh-HK #Chinese (Hong Kong) # zh-TW #Chinese (Traditional) hr #Croatian cs #Czech da #Danish nl #Dutch en #English # en-AU #English (Australian) # en-GB #English (Great Britain) et #Estonian fa #Farsi fi #Finnish fil #Filipino fr #French # fr-CA #French (Canada) ka #Georgian de #German el #Greek iw #Hebrew hi #Hindi hu #Hungarian is #Icelandic id #Indonesian it #Italian ja #Japanese kn #Kannada kk #Kazakh km #Khmer ko #Korean ky #Kyrgyz lo #Lao lv #Latvian lt #Lithuanian mk #Macedonian ms #Malay ml #Malayalam mr #Marathi mn #Mongolian ne #Nepali no #Norwegian pl #Polish pt #Portuguese # pt-BR #Portuguese (Brazil) # pt-PT #Portuguese (Portugal) pa #Punjabi ro #Romanian ru #Russian sr #Serbian # si #Sinhalese sk #Slovak # sl #Slovenian es #Spanish # es-419 #Spanish (Latin America) sw #Swahili ta #Tamil te #Telugu th #Thai uk #Ukrainian ur #Urdu uz #Uzbek vi #Vietnamese zu #Zulu } #enum_languages # https://developers.google.com/maps/documentation/places/web-service/supported_types#table1 enum placeTypes { accounting airport amusement_park aquarium art_gallery atm bakery bank bar beauty_salon bicycle_store book_store bowling_alley bus_station cafe campground car_dealer car_rental car_repair car_wash casino cemetery church city_hall clothing_store convenience_store courthouse dentist department_store doctor drugstore electrician electronics_store embassy fire_station florist funeral_home furniture_store gas_station gym hair_care hardware_store hindu_temple home_goods_store hospital insurance_agency jewelry_store laundry lawyer library light_rail_station liquor_store local_government_office locksmith lodging meal_delivery meal_takeaway mosque movie_rental movie_theater moving_company museum night_club painter park parking pet_store pharmacy physiotherapist plumber police post_office primary_school real_estate_agency restaurant roofing_contractor rv_park school secondary_school shoe_store shopping_mall spa stadium storage store subway_station supermarket synagogue taxi_stand tourist_attraction train_station transit_station travel_agency university veterinary_care zoo } #enum_placeTypes #endregion #region bing enums enum cultureCodes { af #Afrikaans am #Amharic #ar-sa #Arabic (Saudi Arabia) as #Assamese #az-Latn #Azerbaijani (Latin) be #Belarusian bg #Bulgarian #bn-BD #Bangla (Bangladesh) #bn-IN #Bangla (India) bs #Bosnian (Latin) ca #Catalan Spanish #ca-ES-valencia #Valencian cs #Czech cy #Welsh da #Danish de #German (Germany) #de-de #German (Germany)** el #Greek #en-GB #English (United Kingdom) #en-US #English (United States)** es #Spanish (Spain) #es-ES #Spanish (Spain)** #es-US #Spanish (United States)1 #es-MX #Spanish (Mexico)1 et #Estonian eu #Basque fa #Persian fi #Finnish #fil-Latn #Filipino fr #French (France) #fr-FR #French (France)** #fr-CA #French (Canada)2 ga #Irish #gd-Latn #Scottish Gaelic #gl #Galician #gu #Gujarati #ha-Latn #Hausa (Latin) he #Hebrew hi #Hindi hr #Croatian hu #Hungarian hy #Armenian id #Indonesian #ig-Latn #Igbo is #Icelandic it #Italian (Italy) #it-it #Italian (Italy)** ja #Japanese ka #Georgian kk #Kazakh km #Khmer kn #Kannada ko #Korean kok #Konkani #ku-Arab #Central Kurdish #ky-Cyrl #Kyrgyz lb #Luxembourgish lt #Lithuanian lv #Latvian #mi-Latn #Maori mk #Macedonian ml #Malayalam #mn-Cyrl #Mongolian (Cyrillic) mr #Marathi ms #Malay (Malaysia) mt #Maltese nb #Norwegian (Bokmål) ne #Nepali (Nepal) nl #Dutch (Netherlands) #nl-BE #Dutch (Netherlands)** nn #Norwegian (Nynorsk) nso #Sesotho sa Leboa or #Odia pa #Punjabi (Gurmukhi) #pa-Arab #Punjabi (Arabic) pl #Polish #prs-Arab #Dari #pt-BR #Portuguese (Brazil) #pt-PT #Portuguese (Portugal) #qut-Latn #K’iche’ quz #Quechua (Peru) ro #Romanian (Romania) ru #Russian rw #Kinyarwanda #sd-Arab #Sindhi (Arabic) #si #Sinhala sk #Slovak #sl #Slovenian sq #Albanian #sr-Cyrl-BA #Serbian (Cyrillic, Bosnia and Herzegovina) #sr-Cyrl-RS #Serbian (Cyrillic, Serbia) #sr-Latn-RS #Serbian (Latin, Serbia) #sv #Swedish (Sweden) sw #Kiswahili ta #Tamil te #Telugu #tg-Cyrl #Tajik (Cyrillic) th #Thai ti #Tigrinya #tk-Latn #Turkmen (Latin) tn #Setswana tr #Turkish #tt-Cyrl #Tatar (Cyrillic) #ug-Arab #Uyghur uk #Ukrainian ur #Urdu #uz-Latn #Uzbek (Latin) vi #Vietnamese wo #Wolof xh #isiXhosa #yo-Latn #Yoruba #zh-Hans #Chinese (Simplified) #zh-Hant #Chinese (Traditional) zu #isiZulu } #enum_cultureCodes # https://learn.microsoft.com/en-us/bingmaps/rest-services/common-parameters-and-types/type-identifiers/ enum typeIdentifier { AmusementParks # Amusement parks. AntiqueStores # For retail stores that sell antiques. Attractions # Miscellaneous attractions that don't belong to another type. BanksAndCreditUnions Bars # For establishments that serve primarily alcoholic drinks such as beer, wine, liquor, and cocktails for consumption by the patrons on certain premises. BarsGrillsAndPubs # A casual restaurant that serves substantial amount of food and alcoholic beverages on the menu. BelgianRestaurants # Restaurants that primarily serve cuisine from Belgium. Bookstores # For retail stores that primarily sell books, and may also include newspapers, magazines, maps. BreweriesAndBrewPubs # For businesses or entities which brew and process beer on the premises, typically also serving their products in-house to the public. BritishRestaurants # A restaurant that primarily serves cuisine from the British cultural traditions, including English, Welsh, Cornish and Scottish. BuffetRestaurants # A restaurant where food is presented buffet-style and patrons can serve themselves. CDAndRecordStores # Includes music stores that primarily sell music via CDs, Records, Albums, Cassette Tapes. May also sell music accessories for those devices. CafeRestaurants # This casual eating and drinking place offers significant food options, prepared to order, and seating at the premise. CaribbeanRestaurants # A restaurant that primarily serves cuisine from the Caribbean traditions. Carnivals # Carnival attractions. Casinos # Casinos and other gambling establishments. ChildrensClothingStores # For retail stores that primarily sell clothing for children (including infants). ChineseRestaurants # A restaurant that primarily serves cuisine from the Chinese cultural traditions. CigarAndTobaccoShops # For retail stores that sell tobacco and tobacco accessories. CocktailLounges # For bars whose focus is serving and selling alcoholic mixed drinks. CoffeeAndTea # For establishments that primarily serve coffee and/or tea. ComicBookStores # For retail stores that focus sales on comic books, comic magazines, and other comic accessories. Delicatessens # In the United States, a delicatessen store, or deli, is a type of business that is both a grocery store and serves food. DeliveryService # This type includes business which offer the option to deliver prepared dishes to different locations like home or work. DepartmentStores # For retailers that primarily sell a wide range of consumer goods such as clothing, housewares, furniture and appliances, toys, cosmetics. Diners # Diners are characterized by offering a wide range of foods, mostly American, a casual atmosphere, a counter, and late operating hours. DiscountStores # For retail stores that primarily sell products at lower prices than standard retail stores. Discount stores may or may not have various departments offering a wide variety of goods. Donuts # For places that primarily serve donuts. FastFood # For businesses characterized by their quickness, cheap food, and minimal service. FleaMarketsAndBazaars # Where individuals are able to rent a space to display and sell their goods that are usually used/old at a lower price. FrenchRestaurants # A restaurant that primarily serves cuisine from the French cultural traditions. FrozenYogurt # For entities that primarily serve frozen yogurt such as FroYo and Frogurt. FurnitureStores # For retail stores that sell objects (whether new or used) intended to support various human activities such as sitting and sleeping. GermanRestaurants # Restaurants that primarily serve cuisine from Germany. GreekRestaurants # Restaurants that primarily serve cuisine from the Greek cultural traditions. Grocers # Retail entities that provide food products to consumers, including corner stores. Grocery # Retail entities that provide food products to consumers. HawaiianRestaurants # A restaurant that primarily serves cuisine from Hawaiian traditions. HomeImprovementStores # For retail stores that primarily sell hardware for home improvements such as power tools, electrical supplies and other related items. Hospitals HotelsAndMotels HungarianRestaurants # Restaurants that primarily serve food from Hungarian cuisine. IceCreamAndFrozenDesserts # For businesses that primarily serve ice cream and other frozen desserts, like cheese cake. IndianRestaurants # Restaurants that primarily serve cuisine from Indian cultural traditions. ItalianRestaurants # Restaurants that primarily serve cuisine from Italian cultural traditions. JapaneseRestaurants # Restaurants that primarily serve cuisine from Japanese cultural traditions. JewelryAndWatchesStores # For retail stores which sell jewelry and watches, as well as business that purchase gold and silver from the buyer ("cash for gold"). Juices # For businesses offering juices and smoothies. KitchenwareStores # For retail stores that primarily sell tableware, cookware and bakeware. KoreanRestaurants # Restaurants that primarily serve cuisine from Korean cultural traditions. LandmarksAndHistoricalSites # Man-made landmarks and historical sites. LiquorStores # For retail stores that primarily sell liquor, wine, beer and spirits. MallsAndShoppingCenters # For large complexes with various retail shops and interconnecting walkways allowing shoppers to have a complete shopping experience. MensClothingStores # For retail stores that primarily sell clothing specifically designed for men to wear MexicanRestaurants # Restaurants that primarily serve cuisine from Mexican cultural traditions. MiddleEasternRestaurants # Restaurants that primarily serve cuisine from Middle Eastern cultural traditions. MiniatureGolfCourses # Miniature golf courses. MovieTheaters # Movie theaters and houses. Museums # Museums and art galleries. MusicStores # For retail shops which sell music related equipment or offer music related services. OutletStores # For retail shops which sell music related equipment or offer music related services. Parking Parks # Natural parks and gardens. PetShops # for retail stores that primarily sell pets. PetSupplyStores # For retail stores that primarily sell pet supplies. Pizza # Restaurants that primarily serve pizza, including pizza deliveries. PolishRestaurants # Restaurants that primarily serve cuisine from Polish cultural traditions. PortugueseRestaurants # Restaurants that primarily serve cuisine from Portuguese cultural traditions. Pretzels # For businesses, places, kiosks, stands, or carts that primarily sell pretzels. Restaurants # Business entities with the primary purpose of serving prepared-to-order food to the public. RussianAndUkrainianRestaurants # Restaurants that primarily serve cuisine from Russian and/or Ukrainian cultural traditions. Sandwiches # Restaurants that primarily serve sandwiches. SchoolAndOfficeSupplyStores # Includes all office-related products. Pens, pencils, whiteboard markers, binders, mailing/shipping supplies, and basic office machines (fax, media projectors, etc.). Also includes retail-specific supplies, like shopping bags, signs, and cash handling products. All forms and types of calendars, breakroom and office cleaning supplies, and in-person meeting supplies. SeafoodRestaurants # A restaurant that primarily serves seafood, including freshwater fish. ShoeStores # For retail stores that primarily sell footwear. SightseeingTours # Sight-seeing tours. SpanishRestaurants # Restaurants that primarily serve cuisine from Spanish cultural traditions. SportingGoodsStores # For retail stores that primarily sell sport and fitness equipment. SportsBars # Bars with a primary focus on viewing live sporting and entertainment events. SteakHouseRestaurants # Restaurants that primarily serve beef steaks. Supermarkets # Large, warehouse-like retail entities that provide food products to consumers. SushiRestaurants # Restaurants that primarily service sushi, including both cooked and raw seafood. TakeAway # A food establishment that offers the option to purchase prepared dishes for the purpose of being eaten elsewhere. Taverns # Similar to bars, but with additional seating; typically these are businesses which were once residences. ThaiRestaurants # Restaurants that primarily serve cuisine from Thai cultural traditions. TouristInformation # Tourist information booths and visitor centers. ToyAndGameStores # For retail stores that primarily sell toys and games for all ages, including electronic toys, and educational game systems. TurkishRestaurants # Restaurants that primarily serve cuisine from Turkish cultural traditions. VegetarianAndVeganRestaurants # Restaurant that primarily serve vegetarian and/or vegan cuisine. VietnameseRestaurants # Restaurants that primarily serve cuisine from Vietnamese cultural traditions. VitaminAndSupplementStores # For retail stores that primarily sell vitamins and supplements. WomensClothingStores # For retail stores that primarily sell women's clothing. Zoos # Zoos and aquariums. } #enum_typeIdentifier #endregion #endregion <# .SYNOPSIS Formats GeoCode object with easier to understand properties while leaving original properties intact .DESCRIPTION Changes GeoCode object to custom PSType and creates additional properties that contains information most likely to be viewed. .EXAMPLE $results.resourceSets.resources | Format-BingGeoCode Formats GeoCode object results with a set of easier to understand properties .PARAMETER Results GeoCode API results .OUTPUTS Bing.GeoCode .NOTES Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/ Based on code from: https://github.com/Kreloc/PoshGMaps .COMPONENT pwshPlaces #> function Format-BingGeoCode { [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = 'GeoCode API results', ValueFromPipeline = $true)] $Results ) begin { Write-Verbose ('Starting {0}' -f $myinvocation.mycommand) } #begin process { Write-Debug -Message ($Results | Out-String) $Results.PSTypeNames.Insert(0, 'Bing.GeoCode') Write-Debug -Message ($Results.PSTypeNames | Out-String) $updateTypeDataSplat = @{ TypeName = 'Bing.GeoCode' MemberType = 'ScriptProperty' MemberName = 'FormattedAddress' Value = { $this.address.formattedAddress } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'Bing.GeoCode' MemberType = 'ScriptProperty' MemberName = 'Street' Value = { $this.address.addressLine } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'Bing.GeoCode' MemberType = 'ScriptProperty' MemberName = 'City' Value = { $this.address.locality } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'Bing.GeoCode' MemberType = 'ScriptProperty' MemberName = 'Country' Value = { $this.address.countryRegion } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'Bing.GeoCode' MemberType = 'ScriptProperty' MemberName = 'PostalCode' Value = { $this.address.postalCode } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'Bing.GeoCode' MemberType = 'ScriptProperty' MemberName = 'Latitude' Value = { $this.point.coordinates[0] } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'Bing.GeoCode' MemberType = 'ScriptProperty' MemberName = 'Longitude' Value = { $this.point.coordinates[1] } Force = $true } Update-TypeData @updateTypeDataSplat # set a default display of the above properties, all other properties are still there just not displayed $updateTypeDataSplat = @{ TypeName = 'Bing.GeoCode' DefaultDisplayPropertySet = 'name', 'FormattedAddress', 'Street', 'City', 'Country', 'PostalCode', 'Latitude', 'Longitude', 'entityType' DefaultKeyPropertySet = 'name' Force = $true } Update-TypeData @updateTypeDataSplat $Results } #process end { Write-Verbose ('Ending {0}' -f $myinvocation.mycommand) } #end } #Format-BingGeoCode <# .SYNOPSIS Formats Place object with easier to understand properties while leaving original properties intact .DESCRIPTION Changes Place object to custom PSType and creates additional properties that contains information most likely to be viewed. .EXAMPLE $results.resourceSets.resources | Format-BingPlace Formats GeoCode object results with a set of easier to understand properties .PARAMETER Results Place API results .OUTPUTS Bing.Place .NOTES Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/ Based on code from: https://github.com/Kreloc/PoshGMaps .COMPONENT pwshPlaces #> function Format-BingPlace { [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = 'GeoCode API results', ValueFromPipeline = $true)] $Results ) begin { Write-Verbose ('Starting {0}' -f $myinvocation.mycommand) } #begin process { Write-Debug -Message ($Results | Out-String) $Results.PSTypeNames.Insert(0, 'Bing.Place') Write-Debug -Message ($Results.PSTypeNames | Out-String) $updateTypeDataSplat = @{ TypeName = 'Bing.Place' MemberType = 'ScriptProperty' MemberName = 'FormattedAddress' Value = { $this.address.formattedAddress } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'Bing.Place' MemberType = 'ScriptProperty' MemberName = 'Latitude' Value = { $this.point.coordinates[0] } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'Bing.Place' MemberType = 'ScriptProperty' MemberName = 'Longitude' Value = { $this.point.coordinates[1] } Force = $true } Update-TypeData @updateTypeDataSplat # set a default display of the above properties, all other properties are still there just not displayed $updateTypeDataSplat = @{ TypeName = 'Bing.Place' DefaultDisplayPropertySet = 'name', 'FormattedAddress', 'PhoneNumber', 'Website', 'Latitude', 'Longitude', 'entityType' DefaultKeyPropertySet = 'name' Force = $true } Update-TypeData @updateTypeDataSplat $Results } #process end { Write-Verbose ('Ending {0}' -f $myinvocation.mycommand) } #end } #Format-BingPlace <# .SYNOPSIS Formats TimeZone object with easier to understand properties while leaving original properties intact .DESCRIPTION Changes TimeZone object to custom PSType and creates additional properties that contains information most likely to be viewed. .EXAMPLE $results.resourceSets.resources.timeZone | Format-BingTimeZone Formats TimeZone object results with a set of easier to understand properties .PARAMETER Results TimeZone API results .OUTPUTS Bing.TimeZone .NOTES Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/ Based on code from: https://github.com/Kreloc/PoshGMaps .COMPONENT pwshPlaces #> function Format-BingTimeZone { [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = 'TimeZone API results', ValueFromPipeline = $true)] $Results ) begin { Write-Verbose ('Starting {0}' -f $myinvocation.mycommand) } #begin process { Write-Debug -Message ($Results | Out-String) $Results.PSTypeNames.Insert(0, 'Bing.TimeZone') Write-Debug -Message ($Results.PSTypeNames | Out-String) $updateTypeDataSplat = @{ TypeName = 'Bing.TimeZone' MemberType = 'ScriptProperty' MemberName = 'TimeZoneName' Value = { $this.genericName } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'Bing.TimeZone' MemberType = 'ScriptProperty' MemberName = 'TimeZoneShort' Value = { $this.abbreviation } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'Bing.TimeZone' MemberType = 'ScriptProperty' MemberName = 'TimeZoneID' Value = { $this.ianaTimeZoneId } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'Bing.TimeZone' MemberType = 'ScriptProperty' MemberName = 'LocalTime' Value = { $this.convertedTime.localTime } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'Bing.TimeZone' MemberType = 'ScriptProperty' MemberName = 'UTCOffSetDST' Value = { $this.convertedTime.utcOffsetWithDst } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'Bing.TimeZone' MemberType = 'ScriptProperty' MemberName = 'TimeZoneCurrentName' Value = { $this.convertedTime.timeZoneDisplayName } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'Bing.TimeZone' MemberType = 'ScriptProperty' MemberName = 'TimeZoneCurrentShort' Value = { $this.convertedTime.timeZoneDisplayAbbr } Force = $true } Update-TypeData @updateTypeDataSplat # set a default display of the above properties, all other properties are still there just not displayed $updateTypeDataSplat = @{ TypeName = 'Bing.TimeZone' DefaultDisplayPropertySet = 'TimeZoneName', 'TimeZoneShort', 'UTCOffSet', 'TimeZoneID', 'LocalTime', 'TimeZoneCurrentName', 'TimeZoneCurrentShort', 'UTCOffSetDST', 'dstRule' DefaultKeyPropertySet = 'TimeZoneName' Force = $true } Update-TypeData @updateTypeDataSplat $Results } #process end { Write-Verbose ('Ending {0}' -f $myinvocation.mycommand) } #end } #Format-BingTimeZone <# .SYNOPSIS Formats GeoCode object with easier to understand properties while leaving original properties intact .DESCRIPTION Changes GeoCode object to custom PSType and creates additional properties that contains information most likely to be viewed. .EXAMPLE $results.result | Format-GMapGeoCode Formats GeoCode object results with a set of easier to understand properties .PARAMETER Results GeoCode API results .OUTPUTS GMap.GeoCode .NOTES Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/ Based on code from: https://github.com/Kreloc/PoshGMaps .COMPONENT pwshPlaces #> function Format-GMapGeoCode { [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = 'GeoCode API results', ValueFromPipeline = $true)] $Results ) begin { Write-Verbose ('Starting {0}' -f $myinvocation.mycommand) } #begin process { Write-Debug -Message ($Results | Out-String) $Results.PSTypeNames.Insert(0, 'GMap.GeoCode') Write-Debug -Message ($Results.PSTypeNames | Out-String) $updateTypeDataSplat = @{ TypeName = 'GMap.GeoCode' MemberType = 'ScriptProperty' MemberName = 'StreetNumber' Value = { $(($this.address_components | Where-Object { $_.types -contains "street_number" }).long_name) } Force = $true } Write-Verbose ($updateTypeDataSplat | Out-String) Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.GeoCode' MemberType = 'ScriptProperty' MemberName = 'Street' Value = { $($this.address_components | Where-Object { $_.types -contains "route" }).long_name } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.GeoCode' MemberType = 'ScriptProperty' MemberName = 'City' Value = { $($this.address_components | Where-Object { $_.types -contains "locality" }).long_name } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.GeoCode' MemberType = 'ScriptProperty' MemberName = 'Country' Value = { $($this.address_components | Where-Object { $_.types -contains "country" }).long_name } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.GeoCode' MemberType = 'ScriptProperty' MemberName = 'PostalCode' Value = { $($this.address_components | Where-Object { $_.types -contains "postal_code" }).long_name } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.GeoCode' MemberType = 'ScriptProperty' MemberName = 'Latitude' Value = { $this.geometry.location.lat } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.GeoCode' MemberType = 'ScriptProperty' MemberName = 'Longitude' Value = { $this.geometry.location.lng } Force = $true } Update-TypeData @updateTypeDataSplat # set a default display of the above properties, all other properties are still there just not displayed $updateTypeDataSplat = @{ TypeName = 'GMap.GeoCode' DefaultDisplayPropertySet = 'place_id', 'formatted_address', 'StreetNumber', 'Street', 'City', 'Country', 'PostalCode', 'Latitude', 'Longitude', 'types' DefaultKeyPropertySet = 'place_id' Force = $true } Update-TypeData @updateTypeDataSplat $Results } #process end { Write-Verbose ('Ending {0}' -f $myinvocation.mycommand) } #end } #Format-GMapGeoCode <# .SYNOPSIS Formats Nearby Place object with easier to understand properties while leaving original properties intact .DESCRIPTION Changes Nearby Place object to custom PSType and creates additional properties that contains information most likely to be viewed. .EXAMPLE $results.results | Format-GMapNearbyPlace Formats Nearby Place object results with a set of easier to understand properties .PARAMETER Results Nearby Place API results .OUTPUTS GMap.NearbyPlace .NOTES Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/ Based on code from: https://github.com/Kreloc/PoshGMaps .COMPONENT pwshPlaces #> function Format-GMapNearbyPlace { [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = 'Place API results', ValueFromPipeline = $true)] $Results ) begin { Write-Verbose ('Starting {0}' -f $myinvocation.mycommand) } #begin process { Write-Debug -Message ($Results | Out-String) $Results.PSTypeNames.Insert(0, 'GMap.NearbyPlace') Write-Debug -Message ($Results.PSTypeNames | Out-String) $updateTypeDataSplat = @{ TypeName = 'GMap.NearbyPlace' MemberType = 'ScriptProperty' MemberName = 'Latitude' Value = { $this.geometry.location.lat } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.NearbyPlace' MemberType = 'ScriptProperty' MemberName = 'Longitude' Value = { $this.geometry.location.lng } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.NearbyPlace' MemberType = 'ScriptProperty' MemberName = 'Address' Value = { $this.vicinity } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.NearbyPlace' MemberType = 'ScriptProperty' MemberName = 'Open' Value = { $this.opening_hours.open_now } Force = $true } Update-TypeData @updateTypeDataSplat # set a default display of the above properties, all other properties are still there just not displayed $updateTypeDataSplat = @{ TypeName = 'GMap.NearbyPlace' DefaultDisplayPropertySet = 'place_id', 'name', 'Address', 'Latitude', 'Longitude', 'types', 'rating', 'user_ratings_total', 'price_level', 'Open' DefaultKeyPropertySet = 'place_id' Force = $true } Update-TypeData @updateTypeDataSplat $Results } #process end { Write-Verbose ('Ending {0}' -f $myinvocation.mycommand) } #end } #Format-GMapNearbyPlace <# .SYNOPSIS Formats Place object with easier to understand properties while leaving original properties intact .DESCRIPTION Changes Place object to custom PSType and creates additional properties that contains information most likely to be viewed. .EXAMPLE $results.candidates | Format-GMapPlace Formats Place object results with a set of easier to understand properties .PARAMETER Results Place API results .OUTPUTS GMap.Place .NOTES Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/ Based on code from: https://github.com/Kreloc/PoshGMaps .COMPONENT pwshPlaces #> function Format-GMapPlace { [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = 'Place API results', ValueFromPipeline = $true)] $Results ) begin { Write-Verbose ('Starting {0}' -f $myinvocation.mycommand) } #begin process { Write-Debug -Message ($Results | Out-String) $Results.PSTypeNames.Insert(0, 'GMap.Place') Write-Debug -Message ($Results.PSTypeNames | Out-String) $updateTypeDataSplat = @{ TypeName = 'GMap.Place' MemberType = 'ScriptProperty' MemberName = 'Latitude' Value = { $this.geometry.location.lat } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.Place' MemberType = 'ScriptProperty' MemberName = 'Longitude' Value = { $this.geometry.location.lng } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.Place' MemberType = 'ScriptProperty' MemberName = 'Address' Value = { $this.formatted_address } Force = $true } Update-TypeData @updateTypeDataSplat # if ($Contact) { $updateTypeDataSplat = @{ TypeName = 'GMap.Place' MemberType = 'ScriptProperty' MemberName = 'Open' Value = { $this.opening_hours.open_now } Force = $true } Update-TypeData @updateTypeDataSplat # } # set a default display of the above properties, all other properties are still there just not displayed $updateTypeDataSplat = @{ TypeName = 'GMap.Place' DefaultDisplayPropertySet = 'place_id', 'name', 'Address', 'Open', 'rating', 'user_ratings_total', 'price_level', 'Latitude', 'Longitude', 'types' DefaultKeyPropertySet = 'place_id' Force = $true } Update-TypeData @updateTypeDataSplat $Results } #process end { Write-Verbose ('Ending {0}' -f $myinvocation.mycommand) } #end } #Format-GMapPlace <# .SYNOPSIS Formats Detailed Place object with easier to understand properties while leaving original properties intact .DESCRIPTION Changes Detailed Place object to custom PSType and creates additional properties that contains information most likely to be viewed. .EXAMPLE $results.results | Format-GMapPlaceDetail Formats Detailed Place object results with a set of easier to understand properties .PARAMETER Results Detailed Place API results .OUTPUTS GMap.PlaceDetail .NOTES Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/ Based on code from: https://github.com/Kreloc/PoshGMaps .COMPONENT pwshPlaces #> function Format-GMapPlaceDetail { [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = 'Place API results', ValueFromPipeline = $true)] $Results ) begin { Write-Verbose ('Starting {0}' -f $myinvocation.mycommand) } #begin process { Write-Debug -Message ($Results | Out-String) $Results.PSTypeNames.Insert(0, 'GMap.PlaceDetail') Write-Debug -Message ($Results.PSTypeNames | Out-String) $updateTypeDataSplat = @{ TypeName = 'GMap.PlaceDetail' MemberType = 'ScriptProperty' MemberName = 'Latitude' Value = { $this.geometry.location.lat } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.PlaceDetail' MemberType = 'ScriptProperty' MemberName = 'Longitude' Value = { $this.geometry.location.lng } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.PlaceDetail' MemberType = 'ScriptProperty' MemberName = 'Address' Value = { $this.formatted_address } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.PlaceDetail' MemberType = 'ScriptProperty' MemberName = 'Phone' Value = { $this.formatted_phone_number } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.PlaceDetail' MemberType = 'ScriptProperty' MemberName = 'Open' Value = { $this.opening_hours.open_now } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.PlaceDetail' MemberType = 'ScriptProperty' MemberName = 'OpenHours' Value = { $this.opening_hours.weekday_text } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.PlaceDetail' MemberType = 'ScriptProperty' MemberName = 'GoogleMapsURL' Value = { $this.url } Force = $true } Update-TypeData @updateTypeDataSplat # set a default display of the above properties, all other properties are still there just not displayed $updateTypeDataSplat = @{ TypeName = 'GMap.PlaceDetail' DefaultDisplayPropertySet = 'place_id', 'name', 'website', 'Address', 'Phone', 'Open', 'OpenHours', 'GoogleMapsURL', 'rating', 'user_ratings_total', 'price_level', 'Latitude', 'Longitude', 'types' DefaultKeyPropertySet = 'place_id' Force = $true } Update-TypeData @updateTypeDataSplat $Results } #process end { Write-Verbose ('Ending {0}' -f $myinvocation.mycommand) } #end } #Format-GMapPlaceDetail <# .SYNOPSIS Formats Text Place object with easier to understand properties while leaving original properties intact .DESCRIPTION Changes Text Place object to custom PSType and creates additional properties that contains information most likely to be viewed. .EXAMPLE $results.results | Format-GMapPlaceText Formats Text Place object results with a set of easier to understand properties .PARAMETER Results Nearby Place API results .OUTPUTS GMap.PlaceText .NOTES Author: Jake Morrison - @jakemorrison - https://www.techthoughts.info/ Based on code from: https://github.com/Kreloc/PoshGMaps .COMPONENT pwshPlaces #> function Format-GMapPlaceText { [CmdletBinding()] param ( [Parameter(Mandatory = $true, HelpMessage = 'Place API results', ValueFromPipeline = $true)] $Results ) begin { Write-Verbose ('Starting {0}' -f $myinvocation.mycommand) } #begin process { Write-Debug -Message ($Results | Out-String) $Results.PSTypeNames.Insert(0, 'GMap.PlaceText') Write-Debug -Message ($Results.PSTypeNames | Out-String) $updateTypeDataSplat = @{ TypeName = 'GMap.PlaceText' MemberType = 'ScriptProperty' MemberName = 'Latitude' Value = { $this.geometry.location.lat } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.PlaceText' MemberType = 'ScriptProperty' MemberName = 'Longitude' Value = { $this.geometry.location.lng } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.PlaceText' MemberType = 'ScriptProperty' MemberName = 'Address' Value = { $this.formatted_address } Force = $true } Update-TypeData @updateTypeDataSplat $updateTypeDataSplat = @{ TypeName = 'GMap.PlaceText' MemberType = 'ScriptProperty' MemberName = 'Open' Value = { $this.opening_hours.open_now } Force = $true } Update-TypeData @updateTypeDataSplat # set a default display of the above properties, all other properties are still there just not displayed $updateTypeDataSplat = @{ TypeName = 'GMap.PlaceText' DefaultDisplayPropertySet = 'place_id', 'name', 'Address', 'Latitude', 'Longitude', 'types', 'rating', 'user_ratings_total', 'price_level', 'Open' DefaultKeyPropertySet = 'place_id' Force = $true } Update-TypeData @updateTypeDataSplat $Results } #process end { Write-Verbose ('Ending {0}' -f $myinvocation.mycommand) } #end } #Format-GMapPlaceText <# .EXTERNALHELP pwshPlaces-help.xml #> function Find-BingPlace { [CmdletBinding( PositionalBinding = $false, DefaultParameterSetName = 'textquery')] param ( [Parameter(Mandatory = $true, ParameterSetName = 'textquery', HelpMessage = 'A string that contains information about a location, such as an address or landmark name')] [Parameter(ParameterSetName = 'Point', Mandatory = $false)] [Parameter(ParameterSetName = 'Circle', Mandatory = $false)] [Parameter(ParameterSetName = 'Rectangle', Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$Query, [Parameter(Mandatory = $false, ParameterSetName = 'Point', HelpMessage = 'Location bias by point lat')] [ValidateNotNullOrEmpty()] [string]$PointLatitude, [Parameter(Mandatory = $false, ParameterSetName = 'Point', HelpMessage = 'Location bias by point long')] [ValidateNotNullOrEmpty()] [string]$PointLongitude, [Parameter(Mandatory = $false, ParameterSetName = 'Circle', HelpMessage = 'Location bias circular lat')] [ValidateNotNullOrEmpty()] [string]$CircleLatitude, [Parameter(Mandatory = $false, ParameterSetName = 'Circle', HelpMessage = 'Location bias circular long')] [ValidateNotNullOrEmpty()] [string]$CircleLongitude, [Parameter(Mandatory = $false, ParameterSetName = 'Circle', HelpMessage = 'Location bias circular radius')] [ValidateRange(0, 5000)] [string]$CircleRadius, # A string specifying two lat/lng pairs in decimal degrees, representing the south/west and north/east points of a rectangle. [Parameter(Mandatory = $true, ParameterSetName = 'Rectangle', HelpMessage = 'Location bias rectangle south lat')] [ValidateNotNullOrEmpty()] [string]$SouthLatitude, [Parameter(Mandatory = $true, ParameterSetName = 'Rectangle', HelpMessage = 'Location bias rectangle west long')] [ValidateNotNullOrEmpty()] [string]$WestLongitude, [Parameter(Mandatory = $true, ParameterSetName = 'Rectangle', HelpMessage = 'Location bias rectangle north lat')] [ValidateNotNullOrEmpty()] [string]$NorthLatitude, [Parameter(Mandatory = $true, ParameterSetName = 'Rectangle', HelpMessage = 'Location bias rectangle east long')] [ValidateNotNullOrEmpty()] [string]$EastLongitude, [Parameter(Mandatory = $false, HelpMessage = 'The region code, specified as a ccTLD')] [ccTLD]$RegionBias, [Parameter(Mandatory = $false, HelpMessage = 'The language in which to return results')] [languages]$Language, [Parameter(Mandatory = $false, HelpMessage = 'Specifies the maximum number of locations to return in the response')] [ValidateRange(1, 20)] [int]$MaxResults, [Parameter(Mandatory = $true, HelpMessage = 'Bing Maps API Key')] [ValidateNotNullOrEmpty()] [string]$BingMapsAPIKey ) Write-Debug -Message ($PSCmdlet.ParameterSetName) $uri = '{0}{1}' -f $bingMapsBaseURI, 'v1/LocalSearch?output=json' Write-Debug -Message ('Base function URI: {0}' -f $uri) $fQuery = '&query={0}' -f [uri]::EscapeDataString($Query) $uri += $fQuery switch ($PSCmdlet.ParameterSetName) { 'Point' { Write-Debug -Message 'Point specified' $combinedPoint = '{0},{1}' -f $PointLatitude, $PointLongitude $fLocationBias = '&userLocation={0}' -f [uri]::EscapeDataString($combinedPoint) $uri += $fLocationBias } #point 'Circle' { Write-Debug -Message 'Circle specified' $combinedCircle = '{0},{1},{2}' -f $CircleLatitude, $CircleLongitude, $CircleRadius $fLocationBias = '&userCircularMapView={0}' -f [uri]::EscapeDataString($combinedCircle) $uri += $fLocationBias } #circle 'Rectangle' { Write-Debug -Message 'Rectangle specified' $combinedRectangle = '{0},{1},{2},{3}' -f $SouthLatitude, $WestLongitude, $NorthLatitude, $EastLongitude $fLocationBias = '&userMapView={0}' -f [uri]::EscapeDataString($combinedRectangle) $uri += $fLocationBias } #rectangle } #switch_ParameterSetName if ($RegionBias) { Write-Debug -Message ('RegionBias: {0}' -f $RegionBias) $fRegion = '&userRegion={0}' -f $RegionBias $uri += $fRegion } if ($MaxResults) { Write-Debug -Message ('MaxResults: {0}' -f $MaxResults) $fMaxResults = '&maxResults={0}' -f $MaxResults $uri += $fMaxResults } if ($Language) { Write-Debug -Message ('Language: {0}' -f $Language) $fLanguage = '&culture={0}' -f $Language $uri += $fLanguage } Write-Verbose -Message ('Querying Bing API: {0}' -f $uri) Write-Debug -Message 'Adding API key' $fAPIKey = '&key={0}' -f $BingMapsAPIKey $uri += $fAPIKey $invokeRestMethodSplat = @{ Uri = $uri ErrorAction = 'Stop' } try { $results = Invoke-RestMethod @invokeRestMethodSplat } catch { throw $_ } if ($results.statusDescription -ne 'OK') { Write-Warning -Message 'Did not get a successful return from Bing Location API endpoint' $finalResults = $results } elseif (-not ($results.resourceSets.estimatedTotal -ge 1)) { Write-Warning -Message 'No results returned from query' $finalResults = $results } else { $finalResults = ($results.resourceSets.resources | Format-BingPlace) } return $finalResults } #Find-BingPlace <# .EXTERNALHELP pwshPlaces-help.xml #> function Find-BingTimeZone { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ParameterSetName = 'textquery', HelpMessage = 'A string that contains information about a location, such as an address or landmark name')] [ValidateNotNullOrEmpty()] [string]$Query, [Parameter(Mandatory = $true, ParameterSetName = 'Point', HelpMessage = 'Location bias by point lat')] [ValidateNotNullOrEmpty()] [string]$PointLatitude, [Parameter(Mandatory = $true, ParameterSetName = 'Point', HelpMessage = 'Location bias by point long')] [ValidateNotNullOrEmpty()] [string]$PointLongitude, [Parameter(Mandatory = $false, HelpMessage = 'The region code, specified as a ccTLD')] [ccTLD]$RegionBias, [Parameter(Mandatory = $false, HelpMessage = 'The language in which to return results')] [languages]$Language, [Parameter(Mandatory = $true, HelpMessage = 'Bing Maps API Key')] [ValidateNotNullOrEmpty()] [string]$BingMapsAPIKey, [Parameter(Mandatory = $false, HelpMessage = 'Include DST rules')] [switch]$IncludeDSTRules ) Write-Debug -Message ($PSCmdlet.ParameterSetName) switch ($PSCmdlet.ParameterSetName) { 'textquery' { Write-Debug -Message 'Query specified' $uri = '{0}{1}' -f $bingMapsBaseURI, 'v1/TimeZone?output=json' Write-Debug -Message ('Base function URI: {0}' -f $uri) $fQuery = '&query={0}' -f [uri]::EscapeDataString($Query) $uri += $fQuery } #point 'Point' { Write-Debug -Message 'Point specified' Write-Debug -Message 'Location specified' $latLong = 'v1/TimeZone/{0},{1}?output=json' -f $PointLatitude, $PointLongitude $uri = '{0}{1}' -f $bingMapsBaseURI, $latLong Write-Debug -Message ('Base function URI: {0}' -f $uri) } #point } #switch_ParameterSetName if ($RegionBias) { Write-Debug -Message ('RegionBias: {0}' -f $RegionBias) $fRegion = '&userRegion={0}' -f $RegionBias $uri += $fRegion } if ($Language) { Write-Debug -Message ('Language: {0}' -f $Language) $fLanguage = '&culture={0}' -f $Language $uri += $fLanguage } if ($IncludeDSTRules) { Write-Debug -Message 'IncludeDSTRules specified' $fIncludeDSTRules = '&includeDstRules={0}' -f $IncludeDSTRules $uri += $fIncludeDSTRules } Write-Verbose -Message ('Querying Bing API: {0}' -f $uri) Write-Debug -Message 'Adding API key' $fAPIKey = '&key={0}' -f $BingMapsAPIKey $uri += $fAPIKey $invokeRestMethodSplat = @{ Uri = $uri ErrorAction = 'Stop' } try { $results = Invoke-RestMethod @invokeRestMethodSplat } catch { throw $_ } if ($results.statusDescription -ne 'OK') { Write-Warning -Message 'Did not get a successful return from Bing Location API endpoint' $finalResults = $results } elseif (-not ($results.resourceSets.estimatedTotal -ge 1)) { Write-Warning -Message 'No results returned from query' $finalResults = $results } else { if ($PSCmdlet.ParameterSetName -eq 'Point') { $finalResults = ($results.resourceSets.resources.timeZone | Format-BingTimeZone) } else { $finalResults = ($results.resourceSets.resources.timeZoneAtLocation.timeZone | Format-BingTimeZone) } } return $finalResults } #Find-BingTimeZone <# .EXTERNALHELP pwshPlaces-help.xml #> function Find-GMapPlace { [CmdletBinding( PositionalBinding = $false, DefaultParameterSetName = 'textquery')] param ( # 'Phone numbers must be in international format (prefixed by a plus sign ("+"), followed by the country code, then the phone number itself)')] [Parameter(Mandatory = $true, ParameterSetName = 'textquery', HelpMessage = 'Text input that identifies the search target, such as a name, address, or phone number.')] [Parameter(ParameterSetName = 'Point', Mandatory = $false)] [Parameter(ParameterSetName = 'Circle', Mandatory = $false)] [Parameter(ParameterSetName = 'Rectangle', Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$Query, [Parameter(Mandatory = $false, ParameterSetName = 'Point', HelpMessage = 'Location bias by point lat')] [ValidateNotNullOrEmpty()] [string]$PointLatitude, [Parameter(Mandatory = $false, ParameterSetName = 'Point', HelpMessage = 'Location bias by point long')] [ValidateNotNullOrEmpty()] [string]$PointLongitude, [Parameter(Mandatory = $false, ParameterSetName = 'Circle', HelpMessage = 'Location bias circular lat')] [ValidateNotNullOrEmpty()] [string]$CircleLatitude, [Parameter(Mandatory = $false, ParameterSetName = 'Circle', HelpMessage = 'Location bias circular long')] [ValidateNotNullOrEmpty()] [string]$CircleLongitude, [Parameter(Mandatory = $false, ParameterSetName = 'Circle', HelpMessage = 'Location bias circular radius')] [ValidateNotNullOrEmpty()] [string]$CircleRadius, # A string specifying two lat/lng pairs in decimal degrees, representing the south/west and north/east points of a rectangle. [Parameter(Mandatory = $true, ParameterSetName = 'Rectangle', HelpMessage = 'Location bias rectangle south lat')] [ValidateNotNullOrEmpty()] [string]$SouthLatitude, [Parameter(Mandatory = $true, ParameterSetName = 'Rectangle', HelpMessage = 'Location bias rectangle west long')] [ValidateNotNullOrEmpty()] [string]$WestLongitude, [Parameter(Mandatory = $true, ParameterSetName = 'Rectangle', HelpMessage = 'Location bias rectangle north lat')] [ValidateNotNullOrEmpty()] [string]$NorthLatitude, [Parameter(Mandatory = $true, ParameterSetName = 'Rectangle', HelpMessage = 'Location bias rectangle east long')] [ValidateNotNullOrEmpty()] [string]$EastLongitude, [Parameter(Mandatory = $false, HelpMessage = 'return additional contact information')] [switch]$Contact, [Parameter(Mandatory = $false, HelpMessage = 'return additional atmosphere information')] [switch]$Atmosphere, [Parameter(Mandatory = $false, HelpMessage = 'The language in which to return results')] [languages]$Language, [Parameter(Mandatory = $true, HelpMessage = 'Google API Key')] [ValidateNotNullOrEmpty()] [string]$GoogleAPIKey ) <# API Notes: Required parameters input Text input that identifies the search target, such as a name, address, or phone number. The input must be a string. inputtype The type of input. This can be one of either textquery or phonenumber. Phone numbers must be in international format (prefixed by a plus sign ("+"), followed by the country code, then the phone number itself) Optional parameters fields Billing Categories Basic - no charge Contact Atmosphere language locationbias Prefer results in a specified area, by specifying either a radius plus lat/lng, or two lat/lng pairs representing the points of a rectangle. If this parameter is not specified, the API uses IP address biasing by default. IP bias: Instructs the API to use IP address biasing. Pass the string ipbias (this option has no additional parameters). Point: A single lat/lng coordinate. Use the following format: point:lat,lng. Circular: A string specifying radius in meters, plus lat/lng in decimal degrees. Use the following format: circle:radius@lat,lng. Rectangular: A string specifying two lat/lng pairs in decimal degrees #> Write-Debug -Message ($PSCmdlet.ParameterSetName) $uri = '{0}{1}' -f $googleMapsBaseURI, 'place/findplacefromtext/json?' Write-Debug -Message ('Base function URI: {0}' -f $uri) $fQuery = 'input={0}' -f [uri]::EscapeDataString($Query) $uri += $fQuery if ($Query -match '^\+\d+$') { Write-Debug -Message 'Phone number input type' $fInputType = '&inputtype=phonenumber' } else { $fInputType = '&inputtype=textquery' } $uri += $fInputType switch ($PSCmdlet.ParameterSetName) { 'Point' { Write-Debug -Message 'Point specified' $combinedPoint = ':{0},{1}' -f $PointLatitude, $PointLongitude $fLocationBias = '&locationbias=point{0}' -f [uri]::EscapeDataString($combinedPoint) $uri += $fLocationBias } #point 'Circle' { Write-Debug -Message 'Circle specified' $combinedCircle = ':{0}@{1},{2}' -f $CircleRadius, $CircleLatitude, $CircleLongitude $fLocationBias = '&locationbias=circle{0}' -f [uri]::EscapeDataString($combinedCircle) $uri += $fLocationBias } #circle 'Rectangle' { Write-Debug -Message 'Rectangle specified' $combinedRectangle = ':{0},{1}|{2},{3}' -f $SouthLatitude, $WestLongitude, $NorthLatitude, $EastLongitude $fLocationBias = '&locationbias=rectangle{0}' -f [uri]::EscapeDataString($combinedRectangle) $uri += $fLocationBias } #rectangle } #switch_ParameterSetName if ($Language) { Write-Debug -Message ('Language: {0}' -f $Language) $fLanguage = '&language={0}' -f $Language $uri += $fLanguage } $fFields = '&fields=' $basicFields = 'business_status,formatted_address,geometry,icon,icon_mask_base_uri,icon_background_color,name,photo,place_id,plus_code,type' $fFields += [uri]::EscapeDataString($basicFields) if ($Contact) { $contactFields = ',opening_hours' $fFields += [uri]::EscapeDataString($contactFields) } if ($Atmosphere) { $atmosphereFields = ',price_level,rating,user_ratings_total' $fFields += [uri]::EscapeDataString($atmosphereFields) } $uri += $fFields Write-Verbose -Message ('Querying Google API: {0}' -f $uri) Write-Debug -Message 'Adding API key' $fAPIKey = '&key={0}' -f $GoogleAPIKey $uri += $fAPIKey Write-Debug -Message ('Final URI: {0}' -f $uri) $invokeRestMethodSplat = @{ Uri = $uri ErrorAction = 'Stop' } try { $results = Invoke-RestMethod @invokeRestMethodSplat } catch { throw $_ } if ($results.status -ne 'OK') { Write-Warning -Message 'Did not get a successful return from Google Geocode API endpoint' $finalResults = $results } else { $finalResults = ($results.candidates | Format-GMapPlace) } return $finalResults } #Find-GMapPlace <# .EXTERNALHELP pwshPlaces-help.xml #> function Get-GMapPlaceDetail { [CmdletBinding( PositionalBinding = $false, DefaultParameterSetName = 'textquery')] param ( [Parameter(Mandatory = $true, ParameterSetName = 'textquery', HelpMessage = 'The unique identifier of a place in Google Maps')] [Parameter(ParameterSetName = 'atmosphereDetail', Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$PlaceID, [Parameter(Mandatory = $false, HelpMessage = 'return additional contact information')] [switch]$Contact, [Parameter(Mandatory = $false, ParameterSetName = 'atmosphereDetail', HelpMessage = 'return additional atmosphere information')] [switch]$Atmosphere, [Parameter(Mandatory = $false, ParameterSetName = 'atmosphereDetail', HelpMessage = 'The sorting method to use when returning reviews')] [ValidateSet('MostRelevant', 'Newest')] [string]$ReviewSort = 'MostRelevant', [Parameter(Mandatory = $false, HelpMessage = 'The language in which to return results')] [languages]$Language, [Parameter(Mandatory = $false, HelpMessage = 'The region code, specified as a ccTLD')] [ccTLD]$RegionBias, [Parameter(Mandatory = $true, HelpMessage = 'Google API Key')] [ValidateNotNullOrEmpty()] [string]$GoogleAPIKey ) <# API Notes: Required parameters place_id A textual identifier that uniquely identifies a place Optional parameters fields Billing Categories Basic - no charge address_component, adr_address, business_status, formatted_address, geometry, icon, icon_mask_base_uri, icon_background_color, name, permanently_closed (deprecated), photo, place_id, plus_code, type, url, utc_offset, vicinity Contact formatted_phone_number, international_phone_number, opening_hours, website Atmosphere price_level, rating, review, user_ratings_total. reviews_sort The sorting method to use when returning reviews. Can be set to most_relevant (default) or newest. language region #> Write-Debug -Message ($PSCmdlet.ParameterSetName) $uri = '{0}{1}' -f $googleMapsBaseURI, 'place/details/json?' Write-Debug -Message ('Base function URI: {0}' -f $uri) $fPlaceID = 'place_id={0}' -f $PlaceID $uri += $fPlaceID if ($Language) { Write-Debug -Message ('Language: {0}' -f $Language) $fLanguage = '&language={0}' -f $Language $uri += $fLanguage } $fFields = '&fields=' $basicFields = 'address_component,adr_address,business_status,formatted_address,geometry,icon,icon_mask_base_uri,icon_background_color,name,photo,place_id,plus_code,type,url,utc_offset,vicinity' $fFields += [uri]::EscapeDataString($basicFields) if ($Contact) { $contactFields = ',formatted_phone_number,international_phone_number,opening_hours,website' $fFields += [uri]::EscapeDataString($contactFields) } if ($Atmosphere) { $atmosphereFields = ',price_level,rating,review,user_ratings_total' $fFields += [uri]::EscapeDataString($atmosphereFields) } $uri += $fFields if ($RegionBias) { Write-Debug -Message ('RegionBias: {0}' -f $RegionBias) $fRegion = '®ion={0}' -f $RegionBias $uri += $fRegion } switch ($ReviewSort) { 'MostRelevant' { $sortSelection = 'most_relevant' } 'Newest' { $sortSelection = 'newest' } } Write-Debug -Message ('ReviewSort: {0}' -f $sortSelection) $uri += '&reviews_sort={0}' -f $sortSelection Write-Verbose -Message ('Querying Google API: {0}' -f $uri) Write-Debug -Message 'Adding API key' $fAPIKey = '&key={0}' -f $GoogleAPIKey $uri += $fAPIKey Write-Debug -Message ('Final URI: {0}' -f $uri) $invokeRestMethodSplat = @{ Uri = $uri ErrorAction = 'Stop' } try { $results = Invoke-RestMethod @invokeRestMethodSplat } catch { throw $_ } if ($results.status -ne 'OK') { Write-Warning -Message 'Did not get a successful return from Google Geocode API endpoint' $finalResults = $results } else { $finalResults = ($results.result | Format-GMapPlaceDetail) } return $finalResults } #Get-GMapPlaceDetail <# .EXTERNALHELP pwshPlaces-help.xml #> function Invoke-BingGeoCode { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ParameterSetName = 'Address', HelpMessage = 'A string specifying the street line of an address')] [ValidateNotNullOrEmpty()] [string]$AddressLine, [Parameter(Mandatory = $true, ParameterSetName = 'Address', HelpMessage = 'The locality, such as the city or neighborhood, that corresponds to an address')] [ValidateNotNullOrEmpty()] [string]$City, [Parameter(Mandatory = $true, ParameterSetName = 'Address', HelpMessage = 'adminDistrict - A string that contains a subdivision, such as the abbreviation of a US state')] [ValidateNotNullOrEmpty()] [string]$State, [Parameter(Mandatory = $true, ParameterSetName = 'Address', HelpMessage = 'The post code, postal code, or ZIP Code of an address')] [ValidateNotNullOrEmpty()] [string]$PostalCode, [Parameter(Mandatory = $false, ParameterSetName = 'Address', HelpMessage = 'ISO Country code')] [ccTLD]$Country, [Parameter(Mandatory = $true, ParameterSetName = 'Location', HelpMessage = 'Geographic coordinate that specifies the north–south position of a point on the Earths surface')] [ValidateNotNullOrEmpty()] [string]$Latitude, [Parameter(Mandatory = $true, ParameterSetName = 'Location', HelpMessage = 'Geographic coordinate that specifies the east–west position of a point on the Earths surface')] [ValidateNotNullOrEmpty()] [string]$Longitude, [Parameter(Mandatory = $true, ParameterSetName = 'textquery', HelpMessage = 'A string that contains information about a location, such as an address or landmark name')] [ValidateNotNullOrEmpty()] [string]$Query, [Parameter(Mandatory = $false, HelpMessage = 'The language in which to return results')] [languages]$Language, [Parameter(Mandatory = $false, HelpMessage = 'Specifies the maximum number of locations to return in the response')] [ValidateRange(1, 20)] [int]$MaxResults, [Parameter(Mandatory = $true, HelpMessage = 'Bing Maps API Key')] [ValidateNotNullOrEmpty()] [string]$BingMapsAPIKey ) switch ($PSCmdlet.ParameterSetName) { 'Address' { Write-Debug -Message 'Address specified' $uri = '{0}{1}' -f $bingMapsBaseURI, 'v1/Locations?output=json' Write-Debug -Message ('Base function URI: {0}' -f $uri) $fAddressLine = '&addressLine={0}' -f [uri]::EscapeDataString($AddressLine) $uri += $fAddressLine $fCity = '&locality={0}' -f [uri]::EscapeDataString($City) $uri += $fCity $fState = '&adminDistrict={0}' -f [uri]::EscapeDataString($State) $uri += $fState $fPostalCode = '&postalCode={0}' -f [uri]::EscapeDataString($PostalCode) $uri += $fPostalCode $fCountry = '&countryRegion={0}' -f [uri]::EscapeDataString($Country) $uri += $fCountry } #address 'Location' { Write-Debug -Message 'Location specified' $latLong = 'v1/Locations/{0},{1}?output=json' -f $Latitude, $Longitude $uri = '{0}{1}' -f $bingMapsBaseURI, $latLong Write-Debug -Message ('Base function URI: {0}' -f $uri) } #location 'textquery' { Write-Debug -Message 'Query specified' $uri = '{0}{1}' -f $bingMapsBaseURI, 'v1/Locations?output=json' Write-Debug -Message ('Base function URI: {0}' -f $uri) $fQuery = '&query={0}' -f [uri]::EscapeDataString($Query) $uri += $fQuery } #textquery } #switch_ParameterSetName if ($MaxResults) { Write-Debug -Message ('MaxResults: {0}' -f $MaxResults) $fMaxResults = '&maxResults={0}' -f $MaxResults $uri += $fMaxResults } if ($Language) { Write-Debug -Message ('Language: {0}' -f $Language) $fLanguage = '&culture={0}' -f $Language $uri += $fLanguage } Write-Verbose -Message ('Querying Bing API: {0}' -f $uri) Write-Debug -Message 'Adding API key' $fAPIKey = '&key={0}' -f $BingMapsAPIKey $uri += $fAPIKey Write-Debug -Message ('Final URI: {0}' -f $uri) $invokeRestMethodSplat = @{ Uri = $uri ErrorAction = 'Stop' } try { $results = Invoke-RestMethod @invokeRestMethodSplat } catch { throw $_ } if ($results.statusDescription -ne 'OK') { Write-Warning -Message 'Did not get a successful return from Bing Location API endpoint' $finalResults = $results } elseif (-not ($results.resourceSets.estimatedTotal -ge 1)) { Write-Warning -Message 'No results returned from query' $finalResults = $results } else { $finalResults = ($results.resourceSets.resources | Format-BingGeoCode) } return $finalResults } #Invoke-BingGeoCode <# .EXTERNALHELP pwshPlaces-help.xml #> function Invoke-GMapGeoCode { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ParameterSetName = 'Address', HelpMessage = 'The street address or plus code that you want to geocode')] [ValidateNotNullOrEmpty()] [string]$Address, [Parameter(Mandatory = $true, ParameterSetName = 'Location', HelpMessage = 'Geographic coordinate that specifies the north–south position of a point on the Earths surface')] [ValidateNotNullOrEmpty()] [string]$Latitude, [Parameter(Mandatory = $true, ParameterSetName = 'Location', HelpMessage = 'Geographic coordinate that specifies the east–west position of a point on the Earths surface')] [ValidateNotNullOrEmpty()] [string]$Longitude, [Parameter(Mandatory = $true, ParameterSetName = 'PlaceID', HelpMessage = 'The place ID of the place for which you wish to obtain the human-readable address')] [ValidateNotNullOrEmpty()] [string]$PlaceID, [Parameter(Mandatory = $false, HelpMessage = 'The language in which to return results')] [languages]$Language, [Parameter(Mandatory = $false, HelpMessage = 'The region code, specified as a ccTLD')] [ccTLD]$RegionBias, [Parameter(Mandatory = $true, HelpMessage = 'Google API Key')] [ValidateNotNullOrEmpty()] [string]$GoogleAPIKey ) <# API Notes: LAT LONG LOOKUP Required parameters address key Optional parameters bounds language region components Direct API Example: https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=YOUR_API_KEY Reverse geocoding (address lookup) Required parameters latlng key Optional parameters language region result_type location_type #> $uri = '{0}{1}' -f $googleMapsBaseURI, 'geocode/json?' Write-Debug -Message ('Base function URI: {0}' -f $uri) switch ($PSCmdlet.ParameterSetName) { 'Address' { Write-Debug -Message 'Address specified' $fAddress = 'address={0}' -f [uri]::EscapeDataString($address) $uri += $fAddress } #address 'Location' { Write-Debug -Message 'Location specified' $combinedLatLong = '{0},{1}' -f $Latitude, $Longitude $fLatLong = 'latlng={0}' -f [uri]::EscapeDataString($combinedLatLong) $uri += $fLatLong } #location 'PlaceID' { Write-Debug -Message 'PlaceID specified' $fPlaceID = 'place_id={0}' -f $PlaceID $uri += $fPlaceID } #placeID } #switch_ParameterSetName if ($Language) { Write-Debug -Message ('Language: {0}' -f $Language) $fLanguage = '&language={0}' -f $Language $uri += $fLanguage } if ($RegionBias) { Write-Debug -Message ('RegionBias: {0}' -f $RegionBias) $fRegion = '®ion={0}' -f $RegionBias $uri += $fRegion } Write-Verbose -Message ('Querying Google API: {0}' -f $uri) Write-Debug -Message 'Adding API key' $fAPIKey = '&key={0}' -f $GoogleAPIKey $uri += $fAPIKey Write-Debug -Message ('Final URI: {0}' -f $uri) $invokeRestMethodSplat = @{ Uri = $uri ErrorAction = 'Stop' } try { $results = Invoke-RestMethod @invokeRestMethodSplat } catch { throw $_ } if ($results.status -ne 'OK') { Write-Warning -Message 'Did not get a successful return from Google Geocode API endpoint' $finalResults = $results } else { $finalResults = ($results.results | Format-GMapGeoCode) # $finalResults = $results.results # $finalResults = (Format-GMapGeoCode -Results $Results.results) } return $finalResults } #Invoke-GMapGeoCode <# .EXTERNALHELP pwshPlaces-help.xml #> function Search-BingNearbyPlace { [CmdletBinding( PositionalBinding = $false, DefaultParameterSetName = 'PlaceType')] param ( [Parameter(Mandatory = $true, ParameterSetName = 'PlaceType', HelpMessage = 'Restricts the results to places matching the specified type')] [Parameter(ParameterSetName = 'Point', Mandatory = $false)] [Parameter(ParameterSetName = 'Circle', Mandatory = $false)] [Parameter(ParameterSetName = 'Rectangle', Mandatory = $false)] [typeIdentifier]$Type, [Parameter(Mandatory = $false, ParameterSetName = 'Point', HelpMessage = 'Location bias by point lat')] [ValidateNotNullOrEmpty()] [string]$PointLatitude, [Parameter(Mandatory = $false, ParameterSetName = 'Point', HelpMessage = 'Location bias by point long')] [ValidateNotNullOrEmpty()] [string]$PointLongitude, [Parameter(Mandatory = $false, ParameterSetName = 'Circle', HelpMessage = 'Location bias circular lat')] [ValidateNotNullOrEmpty()] [string]$CircleLatitude, [Parameter(Mandatory = $false, ParameterSetName = 'Circle', HelpMessage = 'Location bias circular long')] [ValidateNotNullOrEmpty()] [string]$CircleLongitude, [Parameter(Mandatory = $false, ParameterSetName = 'Circle', HelpMessage = 'Location bias circular radius')] [ValidateRange(0, 5000)] [string]$CircleRadius, # A string specifying two lat/lng pairs in decimal degrees, representing the south/west and north/east points of a rectangle. [Parameter(Mandatory = $true, ParameterSetName = 'Rectangle', HelpMessage = 'Location bias rectangle south lat')] [ValidateNotNullOrEmpty()] [string]$SouthLatitude, [Parameter(Mandatory = $true, ParameterSetName = 'Rectangle', HelpMessage = 'Location bias rectangle west long')] [ValidateNotNullOrEmpty()] [string]$WestLongitude, [Parameter(Mandatory = $true, ParameterSetName = 'Rectangle', HelpMessage = 'Location bias rectangle north lat')] [ValidateNotNullOrEmpty()] [string]$NorthLatitude, [Parameter(Mandatory = $true, ParameterSetName = 'Rectangle', HelpMessage = 'Location bias rectangle east long')] [ValidateNotNullOrEmpty()] [string]$EastLongitude, [Parameter(Mandatory = $false, HelpMessage = 'The region code, specified as a ccTLD')] [ccTLD]$RegionBias, [Parameter(Mandatory = $false, HelpMessage = 'The language in which to return results')] [languages]$Language, [Parameter(Mandatory = $false, HelpMessage = 'Specifies the maximum number of locations to return in the response')] [ValidateRange(1, 20)] [int]$MaxResults, [Parameter(Mandatory = $true, HelpMessage = 'Bing Maps API Key')] [ValidateNotNullOrEmpty()] [string]$BingMapsAPIKey ) Write-Debug -Message ($PSCmdlet.ParameterSetName) $uri = '{0}{1}' -f $bingMapsBaseURI, 'v1/LocalSearch?output=json' Write-Debug -Message ('Base function URI: {0}' -f $uri) $fType = '&type={0}' -f [uri]::EscapeDataString($type) $uri += $fType switch ($PSCmdlet.ParameterSetName) { 'Point' { Write-Debug -Message 'Point specified' $combinedPoint = '{0},{1}' -f $PointLatitude, $PointLongitude $fLocationBias = '&userLocation={0}' -f [uri]::EscapeDataString($combinedPoint) $uri += $fLocationBias } #point 'Circle' { Write-Debug -Message 'Circle specified' $combinedCircle = '{0},{1},{2}' -f $CircleLatitude, $CircleLongitude, $CircleRadius $fLocationBias = '&userCircularMapView={0}' -f [uri]::EscapeDataString($combinedCircle) $uri += $fLocationBias } #circle 'Rectangle' { Write-Debug -Message 'Rectangle specified' $combinedRectangle = '{0},{1},{2},{3}' -f $SouthLatitude, $WestLongitude, $NorthLatitude, $EastLongitude $fLocationBias = '&userMapView={0}' -f [uri]::EscapeDataString($combinedRectangle) $uri += $fLocationBias } #rectangle } #switch_ParameterSetName if ($RegionBias) { Write-Debug -Message ('RegionBias: {0}' -f $RegionBias) $fRegion = '&userRegion={0}' -f $RegionBias $uri += $fRegion } if ($MaxResults) { Write-Debug -Message ('MaxResults: {0}' -f $MaxResults) $fMaxResults = '&maxResults={0}' -f $MaxResults $uri += $fMaxResults } if ($Language) { Write-Debug -Message ('Language: {0}' -f $Language) $fLanguage = '&culture={0}' -f $Language $uri += $fLanguage } Write-Verbose -Message ('Querying Bing API: {0}' -f $uri) Write-Debug -Message 'Adding API key' $fAPIKey = '&key={0}' -f $BingMapsAPIKey $uri += $fAPIKey $invokeRestMethodSplat = @{ Uri = $uri ErrorAction = 'Stop' } try { $results = Invoke-RestMethod @invokeRestMethodSplat } catch { throw $_ } if ($results.statusDescription -ne 'OK') { Write-Warning -Message 'Did not get a successful return from Bing Location API endpoint' $finalResults = $results } elseif (-not ($results.resourceSets.estimatedTotal -ge 1)) { Write-Warning -Message 'No results returned from query' $finalResults = $results } else { $finalResults = ($results.resourceSets.resources | Format-BingPlace) } return $finalResults } #Search-BingNearbyPlace <# .EXTERNALHELP pwshPlaces-help.xml #> function Search-GMapNearbyPlace { [CmdLetBinding( DefaultParameterSetName = 'Location')] param ( [Parameter(Mandatory = $true, ParameterSetName = 'Location', HelpMessage = 'Geographic coordinate that specifies the north–south position of a point on the Earths surface')] [Parameter(ParameterSetName = 'Area', Mandatory = $true)] [Parameter(ParameterSetName = 'Distance', Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Latitude, [Parameter(Mandatory = $true, ParameterSetName = 'Location', HelpMessage = 'Geographic coordinate that specifies the east–west position of a point on the Earths surface')] [Parameter(ParameterSetName = 'Area', Mandatory = $true)] [Parameter(ParameterSetName = 'Distance', Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Longitude, [Parameter(Mandatory = $true, ParameterSetName = 'Area', HelpMessage = 'Distance (in meters) within which to return place results')] [Parameter(ParameterSetName = 'Location', Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Radius, [Parameter(Mandatory = $false, ParameterSetName = 'Area', HelpMessage = 'This option sorts results based on their importance')] # [Parameter(ParameterSetName = 'Location', Mandatory = $false)] [switch]$RankByProminence, [Parameter(Mandatory = $true, ParameterSetName = 'Distance', HelpMessage = 'This option biases search results in ascending order by their distance from the specified location')] # [Parameter(ParameterSetName = 'Location', Mandatory = $false)] [switch]$RankByDistance, [Parameter(Mandatory = $false, HelpMessage = 'A term to be matched against all content that Google has indexed for this place')] [ValidateNotNullOrEmpty()] [string]$Keyword, [Parameter(Mandatory = $false, HelpMessage = 'Restricts the results to places matching the specified type')] [placeTypes]$Type, [Parameter(Mandatory = $false, HelpMessage = 'The language in which to return results')] [languages]$Language, [Parameter(Mandatory = $false, HelpMessage = 'Returns only those places that are open for business at the time the query is sent')] [switch]$OpenNow, [Parameter(Mandatory = $false, HelpMessage = 'Restricts results to only those places within the specified range')] [ValidateNotNullOrEmpty()] [string]$MaxPrice, [Parameter(Mandatory = $false, HelpMessage = 'Restricts results to only those places within the specified range')] [ValidateNotNullOrEmpty()] [string]$MinPrice, [Parameter(Mandatory = $false, HelpMessage = 'TBD')] [switch]$AllSearchResults, [Parameter(Mandatory = $true, HelpMessage = 'Google API Key')] [ValidateNotNullOrEmpty()] [string]$GoogleAPIKey ) <# API Notes: Required parameters location This must be specified as latitude,longitude. radius Defines the distance (in meters) within which to return place results. You may bias results to a specified circle by passing a location and a radius parameter. Doing so instructs the Places service to prefer showing results within that circle; results outside of the defined area may still be displayed. The radius will automatically be clamped to a maximum value depending on the type of search and other parameters. Query Autocomplete: 50,000 meters Text Search: 50,000 meters Optional parameters keyword language maxprice minprice opennow pagetoken radius rankby type #> $uri = '{0}{1}' -f $googleMapsBaseURI, 'place/nearbysearch/json?' Write-Debug -Message ('Base function URI: {0}' -f $uri) $combinedPoint = '{0},{1}' -f $Latitude, $Longitude $fLocation = 'location={0}' -f [uri]::EscapeDataString($combinedPoint) $uri += $fLocation if ($Radius) { Write-Debug -Message ('Radius: {0}' -f $Radius) $fRadius = '&radius={0}' -f $Radius $uri += $fRadius } if ($Keyword) { Write-Debug -Message ('Keyword: {0}' -f $Keyword) $fKeyword = '&keyword={0}' -f $Keyword $uri += $fKeyword } if ($Type) { Write-Debug -Message ('Type: {0}' -f $Type) $fType = '&type={0}' -f $Type $uri += $fType } if ($Language) { Write-Debug -Message ('Language: {0}' -f $Language) $fLanguage = '&language={0}' -f $Language $uri += $fLanguage } if ($OpenNow) { $cOpenNow = 'openNow:true' $fOpenNow = '&{0}' -f [uri]::EscapeDataString($cOpenNow) $uri += $fOpenNow } if ($RankByProminence) { $fRankBy = '&rankby=prominence' $uri += $fRankBy } if ($RankByDistance) { $fRankBy = '&rankby=distance' $uri += $fRankBy } if ($MaxPrice) { Write-Debug -Message ('MaxPrice: {0}' -f $MaxPrice) $fMaxPrice = '&maxprice={0}' -f $MaxPrice $uri += $fMaxPrice } if ($MinPrice) { Write-Debug -Message ('MinPrice: {0}' -f $MinPrice) $fMinPrice = '&minprice={0}' -f $MinPrice $uri += $fMinPrice } Write-Verbose -Message ('Querying Google API: {0}' -f $uri) Write-Debug -Message 'Adding API key' $fAPIKey = '&key={0}' -f $GoogleAPIKey $uri += $fAPIKey Write-Debug -Message ('Final URI: {0}' -f $uri) $allResults = [System.Collections.ArrayList]::new() $invokeRestMethodSplat = @{ Uri = $uri ErrorAction = 'Stop' } try { $results = Invoke-RestMethod @invokeRestMethodSplat } catch { throw $_ } if ($results.status -eq 'OK' -and $AllSearchResults) { $results.results | ForEach-Object { [void]$allResults.Add($_) } $i = 0 $pageToken = $results.next_page_token while ($null -ne $pageToken) { Write-Debug -Message ('Run # - {0}' -f $i) #_________________________________________________________________________ # reconstruct URI for pagetoken use $loopURI = 'https://maps.googleapis.com/maps/api/place/nearbysearch/json?' $loopURI += 'pagetoken={0}' -f $pageToken $loopURI += $fAPIKey #_________________________________________________________________________ <# There is a short delay between when a next_page_token is issued, and when it will become valid. Requesting the next page before it is available will return an INVALID_REQUEST response. This sleep is necessary. the api backend needs time to catch up. TODO: add logic to check for INVALID_REQUEST and retry #> Start-Sleep -Seconds 4 #_________________________________________________________________________ # resets $results = $null $pageToken = $null #_________________________________________________________________________ $invokeRestMethodSplat = @{ Uri = $loopURI ErrorAction = 'Stop' } try { $results = Invoke-RestMethod @invokeRestMethodSplat } catch { throw $_ } #_________________________________________________________________________ $pageToken = $results.next_page_token $results.results | ForEach-Object { [void]$allResults.Add($_) } $i++ #_________________________________________________________________________ } $finalResults = $allResults | Format-GMapNearbyPlace } elseif ($results.status -ne 'OK' ) { Write-Warning -Message 'Did not get a succcessful return from Google Geocode API endpoint' $finalResults = $results } else { $finalResults = ($results.results | Format-GMapNearbyPlace) } return $finalResults } #Search-GMapNearbyPlace <# .EXTERNALHELP pwshPlaces-help.xml #> function Search-GMapText { [CmdletBinding( DefaultParameterSetName = 'textquery')] param ( [Parameter(Mandatory = $true, ParameterSetName = 'textquery', HelpMessage = 'Text string on which to search')] [Parameter(ParameterSetName = 'Location', Mandatory = $false)] [Parameter(ParameterSetName = 'Area', Mandatory = $false)] [Parameter(ParameterSetName = 'Distance', Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$Query, [Parameter(Mandatory = $true, ParameterSetName = 'Location', HelpMessage = 'Geographic coordinate that specifies the north–south position of a point on the Earths surface')] [Parameter(ParameterSetName = 'Area', Mandatory = $false)] [Parameter(ParameterSetName = 'Distance', Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$Latitude, [Parameter(Mandatory = $true, ParameterSetName = 'Location', HelpMessage = 'Geographic coordinate that specifies the east–west position of a point on the Earths surface')] [Parameter(ParameterSetName = 'Area', Mandatory = $false)] [Parameter(ParameterSetName = 'Distance', Mandatory = $false)] [ValidateNotNullOrEmpty()] [string]$Longitude, [Parameter(Mandatory = $true, ParameterSetName = 'Area', HelpMessage = 'Distance (in meters) within which to return place results')] [ValidateNotNullOrEmpty()] [string]$Radius, [Parameter(Mandatory = $false, ParameterSetName = 'Area', HelpMessage = 'This option sorts results based on their importance')] [switch]$RankByProminence, [Parameter(Mandatory = $true, ParameterSetName = 'Distance', HelpMessage = 'This option biases search results in ascending order by their distance from the specified location')] [switch]$RankByDistance, [Parameter(Mandatory = $false, HelpMessage = 'Restricts the results to places matching the specified type')] [placeTypes]$Type, [Parameter(Mandatory = $false, HelpMessage = 'The language in which to return results')] [languages]$Language, [Parameter(Mandatory = $false, HelpMessage = 'The region code, specified as a ccTLD')] [ccTLD]$RegionBias, [Parameter(Mandatory = $false, HelpMessage = 'Returns only those places that are open for business at the time the query is sent')] [switch]$OpenNow, [Parameter(Mandatory = $false, HelpMessage = 'Restricts results to only those places within the specified range')] [ValidateNotNullOrEmpty()] [string]$MaxPrice, [Parameter(Mandatory = $false, HelpMessage = 'Restricts results to only those places within the specified range')] [ValidateNotNullOrEmpty()] [string]$MinPrice, [Parameter(Mandatory = $false, HelpMessage = 'By default 20 results are returned from a standard search. Using this switch increases the search results from 20 to the maximum of 60')] [switch]$AllSearchResults, [Parameter(Mandatory = $true, HelpMessage = 'Google API Key')] [ValidateNotNullOrEmpty()] [string]$GoogleAPIKey ) <# API Notes: Required parameters query radius Defines the distance (in meters) within which to return place results. You may bias results to a specified circle by passing a location and a radius parameter. Doing so instructs the Places service to prefer showing results within that circle; results outside of the defined area may still be displayed. The radius will automatically be clamped to a maximum value depending on the type of search and other parameters. Query Autocomplete: 50,000 meters Text Search: 50,000 meters Optional parameters language location maxprice minprice opennow pagetoken region type #> $uri = '{0}{1}' -f $googleMapsBaseURI, 'place/textsearch/json?' Write-Debug -Message ('Base function URI: {0}' -f $uri) $fQuery = 'query={0}' -f [uri]::EscapeDataString($Query) $uri += $fQuery if ($Latitude -and $Longitude) { $combinedPoint = '{0},{1}' -f $Latitude, $Longitude $fLocation = '&location={0}' -f [uri]::EscapeDataString($combinedPoint) $uri += $fLocation } if ($Radius) { Write-Debug -Message ('Radius: {0}' -f $Radius) $fRadius = '&radius={0}' -f $Radius $uri += $fRadius } if ($Type) { Write-Debug -Message ('Type: {0}' -f $Type) $fType = '&type={0}' -f $Type $uri += $fType } if ($Language) { Write-Debug -Message ('Language: {0}' -f $Language) $fLanguage = '&language={0}' -f $Language $uri += $fLanguage } if ($RegionBias) { Write-Debug -Message ('RegionBias: {0}' -f $RegionBias) $fRegion = '®ion={0}' -f $RegionBias $uri += $fRegion } if ($OpenNow) { $cOpenNow = 'openNow:true' $fOpenNow = '&{0}' -f [uri]::EscapeDataString($cOpenNow) $uri += $fOpenNow } if ($RankByProminence) { $fRankBy = '&rankby=prominence' $uri += $fRankBy } if ($RankByDistance) { $fRankBy = '&rankby=distance' $uri += $fRankBy } if ($MaxPrice) { Write-Debug -Message ('MaxPrice: {0}' -f $MaxPrice) $fMaxPrice = '&maxprice={0}' -f $MaxPrice $uri += $fMaxPrice } if ($MinPrice) { Write-Debug -Message ('MinPrice: {0}' -f $MinPrice) $fMinPrice = '&minprice={0}' -f $MinPrice $uri += $fMinPrice } Write-Verbose -Message ('Querying Google API: {0}' -f $uri) Write-Debug -Message 'Adding API key' $fAPIKey = '&key={0}' -f $GoogleAPIKey $uri += $fAPIKey Write-Debug -Message ('Final URI: {0}' -f $uri) $allResults = [System.Collections.ArrayList]::new() $invokeRestMethodSplat = @{ Uri = $uri ErrorAction = 'Stop' } try { $results = Invoke-RestMethod @invokeRestMethodSplat } catch { throw $_ } if ($results.status -eq 'OK' -and $AllSearchResults) { $results.results | ForEach-Object { [void]$allResults.Add($_) } $i = 0 $pageToken = $results.next_page_token while ($null -ne $pageToken) { Write-Debug -Message ('Run # - {0}' -f $i) #_________________________________________________________________________ # reconstruct URI for pagetoken use $loopURI = 'https://maps.googleapis.com/maps/api/place/textsearch/json?' $loopURI += 'pagetoken={0}' -f $pageToken $loopURI += $fAPIKey #_________________________________________________________________________ <# There is a short delay between when a next_page_token is issued, and when it will become valid. Requesting the next page before it is available will return an INVALID_REQUEST response. This sleep is necessary. the api backend needs time to catch up. TODO: add logic to check for INVALID_REQUEST and retry #> Start-Sleep -Seconds 4 #_________________________________________________________________________ # resets $results = $null $pageToken = $null #_________________________________________________________________________ $invokeRestMethodSplat = @{ Uri = $loopURI ErrorAction = 'Stop' } try { $results = Invoke-RestMethod @invokeRestMethodSplat } catch { throw $_ } #_________________________________________________________________________ $pageToken = $results.next_page_token $results.results | ForEach-Object { [void]$allResults.Add($_) } $i++ #_________________________________________________________________________ } $finalResults = $allResults | Format-GMapPlaceText } elseif ($results.status -ne 'OK' ) { Write-Warning -Message 'Did not get a succcessful return from Google Geocode API endpoint' $finalResults = $results } else { $finalResults = ($results.results | Format-GMapPlaceText) } return $finalResults } #Search-GMapText |