WoW.psm1
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidLongLines', '', Justification = 'Contains long links.')] [CmdletBinding()] param() if ($PSVersionTable.PSVersion -lt '6.0') { [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSAvoidAssignmentToAutomaticVariable', '', Justification = 'Compatibility with PowerShell 6.0 and newer.' )] $IsWindows = [System.Environment]::OSVersion.Platform -eq 'Win32NT' } $scriptName = 'WoW' Write-Verbose "[$scriptName] - Importing module" #region - From [classes] Write-Verbose "[$scriptName] - [classes] - Processing folder" #region - From [classes] - [Classes] Write-Verbose "[$scriptName] - [classes] - [Classes] - Importing" $script:ClassMap = @( [PSCustomObject]@{ ClassID = 1 ClassName = 'Warrior' ColorHex = '#C79C6E' ColorFracR = 0.78 ColorFracG = 0.61 ColorFracB = 0.43 ColorDecR = 199 ColorDecG = 156 ColorDecB = 110 }, # 1 - Warrior [PSCustomObject]@{ ClassID = 2 ClassName = 'Paladin' ColorHex = '#F58CBA' ColorFracR = 0.96 ColorFracG = 0.55 ColorFracB = 0.73 ColorDecR = 245 ColorDecG = 140 ColorDecB = 186 }, # 2 - Paladin [PSCustomObject]@{ ClassID = 3 ClassName = 'Hunter' ColorHex = '#ABD473' ColorFracR = 0.67 ColorFracG = 0.83 ColorFracB = 0.45 ColorDecR = 171 ColorDecG = 212 ColorDecB = 115 }, # 3 - Hunter [PSCustomObject]@{ ClassID = 4 ClassName = 'Rogue' ColorHex = '#FFF569' ColorFracR = 1.00 ColorFracG = 0.96 ColorFracB = 0.41 ColorDecR = 255 ColorDecG = 245 ColorDecB = 105 }, # 4 - Rogue [PSCustomObject]@{ ClassID = 5 ClassName = 'Priest' ColorHex = '#FFFFFF' ColorFracR = 1.00 ColorFracG = 1.00 ColorFracB = 1.00 ColorDecR = 255 ColorDecG = 255 ColorDecB = 255 }, # 5 - Priest [PSCustomObject]@{ ClassID = 6 ClassName = 'Death Knight' ColorHex = '#C41F3B' ColorFracR = 0.77 ColorFracG = 0.12 ColorFracB = 0.23 ColorDecR = 196 ColorDecG = 31 ColorDecB = 59 }, # 6 - Death Knight [PSCustomObject]@{ ClassID = 7 ClassName = 'Shaman' ColorHex = '#0070DE' ColorFracR = 0.00 ColorFracG = 0.44 ColorFracB = 0.87 ColorDecR = 0 ColorDecG = 112 ColorDecB = 222 }, # 7 - Shaman [PSCustomObject]@{ ClassID = 8 ClassName = 'Mage' ColorHex = '#69CCF0' ColorFracR = 0.41 ColorFracG = 0.80 ColorFracB = 0.94 ColorDecR = 105 ColorDecG = 204 ColorDecB = 240 }, # 8 - Mage [PSCustomObject]@{ ClassID = 9 ClassName = 'Warlock' ColorHex = '#9482C9' ColorFracR = 0.58 ColorFracG = 0.51 ColorFracB = 0.79 ColorDecR = 148 ColorDecG = 130 ColorDecB = 201 }, # 9 - Warlock [PSCustomObject]@{ ClassID = 10 ClassName = 'Monk' ColorHex = '#00FF96' ColorFracR = 0.00 ColorFracG = 1.00 ColorFracB = 0.59 ColorDecR = 0 ColorDecG = 255 ColorDecB = 150 }, # 10 - Monk [PSCustomObject]@{ ClassID = 11 ClassName = 'Druid' ColorHex = '#FF7D0A' ColorFracR = 1.00 ColorFracG = 0.49 ColorFracB = 0.04 ColorDecR = 255 ColorDecG = 125 ColorDecB = 10 }, # 11 - Druid [PSCustomObject]@{ ClassID = 12 ClassName = 'Demon Hunter' ColorHex = '#A330C9' ColorFracR = 0.64 ColorFracG = 0.19 ColorFracB = 0.79 ColorDecR = 163 ColorDecG = 48 ColorDecB = 201 } # 12 - Demon Hunter # Missing Evoker ) enum Role { Tank Healer Damage } enum Faction { Alliance = 0 Horde = 1 Neutral = 2 } enum Gender { Male = 0 Female = 1 Unknown = $null } class Account { [string]$Name [bool]$IsMain [string]$FolderPath [Character[]]$Characters [string]$SettingsFolderPath [string]$ConfigCachePath [string]$BindingsCachePath [string]$MacrosCachePath Account ( [string]$Name ) { $this.Name = $Name } [string]ToString() { return $this.Name } } class Addon { [string]$Name [string]$Interface [string]$SavedVariables [string]$AccountSettingsFile [string]$AccountSettingsFileBackup [string]$SavedVariablesPerCharacter [string]$CharacterSettingsFile [string]$CharacterSettingsFileBackup [string]$RequiredDeps [string]$OptionalDeps [string]$DefaultState [string]$AddonFilePath [string]$AddonFile Addon() {} [string]ToString() { return $this.Name } } class AzeriteEssence { [string]$Name [int]$ID [bool]$Valid [bool]$Unlocked [int]$Icon [int]$Rank AzeriteEssence( [string]$Name, [int]$ID, [bool]$Valid, [bool]$Unlocked, [int]$Icon, [int]$Rank ) { $this.Name = $Name $this.ID = $ID $this.Valid = $Valid $this.Unlocked = $Unlocked $this.Icon = $Icon $this.Rank = $Rank } [string]ToString() { return $this.Name } } class PlayableClass { [UInt16]$ID [string]$Name [PowerType]$PowerType PlayableClass() {} PlayableClass( [UInt16]$ID, [string]$Name, [PowerType]$PowerType ) { $this.ID = $ID $this.Name = $Name $this.PowerType = $PowerType } [string]ToString() { return $this.Name } } class Character { [UInt16]$ID [string]$Name [Account]$Account [Realm]$Realm [string]$Region [Gender]$Gender [Faction]$Faction [Race]$Race [PlayableClass]$Class [bool]$IsMainForClass [bool]$IsMain [Specialization]$Specialization [UInt16]$Level [string]$Guild [int]$AchievementPoints [datetime]$LastPlayed [UInt16]$averageItemLevel [UInt16]$averageItemLevelEquipped [string]$FolderPath [string]$SettingsFolderPath [string]$AddOnsFilePath [string]$BindingsCachePath [string]$ConfigCachePath [string]$MacrosCachePath [double]$Gold [Currency[]]$Currency [AzeriteEssence[]]$AzeriteEssences [timespan]$PlayedLevel [timespan]$PlayedTotal [bool]$DailyCurrent [datetime]$DailyReset [bool]$BiWeeklyCurrent [datetime]$BiWeeklyReset [bool]$WeeklyCurrent [datetime]$WeeklyReset [bool]$isResting [UInt16]$ArtifactLevel [double]$ArtifactProgress [string]$Zone [UInt16]$CloakLevel [UInt16]$CorruptionResistance [bool]$Warmode [bool]$VisionUnlocked [bool]$Vision10 [bool]$Vision30 [bool]$Vision50 [bool]$Vision51 [bool]$Vision52 [bool]$Vision53 [bool]$Vision54 [bool]$Vision55 [bool]$VisionCompleted [string]$Vision [UInt16]$KeyBest [string]$KeyBagName [UInt16]$KeyBagLevel [UInt16]$WarTornWeeklyMax [UInt16]$WarTornEarnedThisWeek [UInt16]$WarTornweeklyAvailable [UInt16]$WarTornTotalMax [UInt16]$WarTornTotal [double]$RIOScore [double]$RIOScoreTank [double]$RIOScoreHealer [double]$RIOScoreDPS [string]$AssultUld [string]$AssultVale [string]$EmiLeg1 [string]$EmiLeg2 [string]$EmiLeg3 [string]$EmiBFA1 [string]$EmiBFA2 [string]$EmiBFA3 [bool]$HasNewMail [int]$Durability Character() {} [string]ToString() { return $this.Name + ' - ' + $this.Realm.Name } } class Currency { [UInt16]$ID [string]$Name [int]$Amount Currency() {} Currency( [UInt16]$ID, [string]$Name, [int]$Amount ) { $this.ID = $ID $this.Name = $Name $this.Amount = $Amount } [string]ToString() { return $this.Amount + 'x ' + $this.Name } } class PowerType { [UInt16]$ID [string]$Name PowerType() {} PowerType( [UInt16]$ID, [string]$Name ) { $this.ID = $ID $this.Name = $Name } [string]ToString() { return $this.Name } } class Race { [UInt16]$ID [string]$Name [Faction]$Faction [bool]$IsSelectable [bool]$IsAlliedRace Race() {} Race ( [UInt16]$ID, [string]$Name, [Faction]$Faction, [bool]$IsSelectable, [bool]$IsAlliedRace ) { $this.ID = $ID $this.Name = $Name $this.Faction = $Faction $this.IsSelectable = $IsSelectable $this.IsAlliedRace = $IsAlliedRace } [string]ToString() { return $this.Name } } class Realm { [UInt16]$ID [string]$Name [string]$Region [string]$Category [string]$Locale [string]$Timezone [string]$Type [bool]$IsTournament [string]$Slug Realm() {} Realm ( [UInt16]$ID, [string]$Name, [string]$Region, [string]$Category, [string]$Locale, [string]$Timezone, [string]$Type, [bool]$IsTournament, [string]$Slug ) { $this.ID = $ID $this.Name = $Name $this.Region = $Region $this.Category = $Category $this.Locale = $Locale $this.Timezone = $Timezone $this.Type = $Type $this.IsTournament = $IsTournament $this.Slug = $Slug } Realm ( [string]$Name ) { $this.Name = $Name } [string]ToString() { return $this.Name } } class Specialization { [UInt16]$ID [string]$Name [string]$Description [PowerType]$PowerType [Role]$Role Specialization() {} Specialization( [UInt16]$ID, [string]$Name, [string]$Description, [Role]$Role ) { $this.ID = $ID $this.Name = $Name $this.Description = $Description $this.Role = $Role } [string]ToString() { return $this.Name } } Write-Verbose "[$scriptName] - [classes] - [Classes] - Done" #endregion - From [classes] - [Classes] Write-Verbose "[$scriptName] - [classes] - Done" #endregion - From [classes] #region - From [private] Write-Verbose "[$scriptName] - [private] - Processing folder" #region - From [private] - [Account] Write-Verbose "[$scriptName] - [private] - [Account] - Processing folder" #region - From [private] - [Account] - [Export-WoWAccount] Write-Verbose "[$scriptName] - [private] - [Account] - [Export-WoWAccount] - Importing" function Export-WoWAccount { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> Get-WoWAccount | ConvertTo-Json -EnumsAsStrings | Out-File -FilePath "$Script:WoW_Folder_Cache\Accounts.json" -Force } Write-Verbose "[$scriptName] - [private] - [Account] - [Export-WoWAccount] - Done" #endregion - From [private] - [Account] - [Export-WoWAccount] #region - From [private] - [Account] - [Import-WoWAccount] Write-Verbose "[$scriptName] - [private] - [Account] - [Import-WoWAccount] - Importing" function Import-WoWAccount { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> $CacheFilePath = "$Script:WoW_Folder_Cache\Accounts.json" if (Test-Path $CacheFilePath) { $ImportedAccounts = Get-Content $CacheFilePath | ConvertFrom-Json foreach ($ImportedAccount in $ImportedAccounts) { $Account = [Account]($Script:WoW_Accounts | Where-Object Name -Match $ImportedAccount.Name | Select-Object -First 1) $Account.IsMain = $ImportedAccount.IsMain } } else { Write-WoWVerbose 'Import-WoWAccount: Nothing to import' } } Write-Verbose "[$scriptName] - [private] - [Account] - [Import-WoWAccount] - Done" #endregion - From [private] - [Account] - [Import-WoWAccount] #region - From [private] - [Account] - [Initialize-WoWAccount] Write-Verbose "[$scriptName] - [private] - [Account] - [Initialize-WoWAccount] - Importing" function Initialize-WoWAccount { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER WoWAccountsFolderPath Parameter description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] [OutputType([Account[]])] param( $WoWAccountsFolderPath = $Script:WoW_Folder_Accounts ) [Account[]]$Accounts = $null Write-WoWVerbose 'Accounts: Finding' $AccountFolders = $WoWAccountsFolderPath | Get-ChildItem -Directory | Where-Object Name -NE SavedVariables | Select-Object Name, FullName | Sort-Object name Write-WoWVerbose "Accounts: Found $($AccountFolders.count)" Write-WoWVerbose 'Accounts: Processing' $i = 0 foreach ($AccountFolder in $AccountFolders) { $i++ $Status = "$i/$($AccountFolders.count)" Write-WoWVerbose "Accounts: Processing: $Status $($AccountFolder.Name)" $Account = [Account]::new($AccountFolder.Name) $Account.FolderPath = $AccountFolder.FullName $Account.SettingsFolderPath = "$($Account.FolderPath)\SavedVariables" $Account.ConfigCachePath = "$($Account.FolderPath)\config-cache.wtf" $Account.BindingsCachePath = "$($Account.FolderPath)\bindings-cache.wtf" $Account.MacrosCachePath = "$($Account.FolderPath)\macros-cache.txt" $Account.IsMain = $false $Accounts += $Account Write-WoWVerbose "Accounts: Processing: $Status $($AccountFolder.Name): Done" } Write-WoWVerbose 'Accounts: Processing: Done' return $Accounts | Sort-Object name } Write-Verbose "[$scriptName] - [private] - [Account] - [Initialize-WoWAccount] - Done" #endregion - From [private] - [Account] - [Initialize-WoWAccount] Write-Verbose "[$scriptName] - [private] - [Account] - Done" #endregion - From [private] - [Account] #region - From [private] - [Addon] Write-Verbose "[$scriptName] - [private] - [Addon] - Processing folder" #region - From [private] - [Addon] - [Initialize-WoWAddon] Write-Verbose "[$scriptName] - [private] - [Addon] - [Initialize-WoWAddon] - Importing" function Initialize-WoWAddon { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER WoWAddonsFolderPath Parameter description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] [OutputType([Addon[]])] param( [Parameter(Mandatory)] [string] $WoWAddonsFolderPath ) [Addon[]]$Addons = $null Write-WoWVerbose 'Addons: Finding' $WoWAddonsFolders = $WoWAddonsFolderPath | Get-ChildItem -Directory $AddonTOCFiles = $WoWAddonsFolders | Get-ChildItem | Where-Object name -Like *.toc | Sort-Object name Write-WoWVerbose "Addons: Found $($AddonTOCFiles.count)" Write-WoWVerbose 'Addons: Processing' $i = 0 foreach ($AddonTOCFile in $AddonTOCFiles) { $i++ $Status = "$i/$($AddonTOCFiles.count)" Write-WoWVerbose "Addons: Processing: $Status $($AddonTOCFile.Name)" $Content = Get-Content -Path $AddonTOCFile.FullName $Addon = [Addon]::new() $Addon.AddonFilePath = $AddonTOCFile.FullName $Addon.AddonFile = $AddonTOCFile.Name $SettingsFileName = "$($AddonTOCFile.BaseName).lua" # $Line = $Content[0] foreach ($Line in $Content) { if ($Line -like '*##*Title:*') { $Text = '' $Text = ($Line -split 'Title:').trim()[-1] $Text = $Text.Replace('|r', '') $Text = $Text.Replace('|c', '#|') $Text = $Text.Split('#') $Text = $Text.trim() $Title = $null # $Part = $Text[0] foreach ($Part in $Text) { if ($Part -like '|*') { $Part = $Part.Substring(9) } $Title += $Part } $Addon.Name = $Title } if ($Line -like '*##*Interface:*') { $Interface = ($Line -split 'Interface:').trim()[-1] $Addon.Interface = $Interface } if ($Line -like '*##*SavedVariables:*') { [string[]]$SavedVariables = ($Line -split 'SavedVariables:').trim() $SavedVariables = $SavedVariables[1..($SavedVariables.Length - 1)] $Addon.SavedVariables = $SavedVariables.split(',').Trim() $Addon.AccountSettingsFile = "$SettingsFileName" $Addon.AccountSettingsFileBackup = "$SettingsFileName.bak" } if ($Line -like '*##*SavedVariablesPerCharacter:*') { [string[]]$SavedVariablesPerCharacter = ($Line -split 'SavedVariablesPerCharacter:').trim() $SavedVariablesPerCharacter = [string[]]$SavedVariablesPerCharacter[1..($SavedVariablesPerCharacter.Length - 1)] $Addon.SavedVariablesPerCharacter = $SavedVariablesPerCharacter.split(',').Trim() $Addon.CharacterSettingsFile = "$SettingsFileName" $Addon.CharacterSettingsFileBackup = "$SettingsFileName.bak" } if ($Line -like '*##*RequiredDeps:*') { [string[]]$RequiredDeps = ($Line -split 'RequiredDeps:').trim() $RequiredDeps = [string[]]$RequiredDeps[1..($RequiredDeps.Length - 1)] $RequiredDeps = $RequiredDeps.split(',').Trim() $Addon.RequiredDeps = $RequiredDeps } if ($Line -like '*##*OptionalDeps:*') { [string[]]$OptionalDeps = ($Line -split 'OptionalDeps:').trim() $OptionalDeps = [string[]]$OptionalDeps[1..($OptionalDeps.Length - 1)] $OptionalDeps = $OptionalDeps.split(',').Trim() $Addon.OptionalDeps = $OptionalDeps } if ($Line -like '*##*DefaultState:*') { $DefaultState = ($Line -split 'DefaultState:').trim()[-1] $Addon.DefaultState = $DefaultState } } $Addons += $Addon Write-WoWVerbose "Addons: Processing: $Status $($AddonTOCFile.Name): Done" } Write-WoWVerbose 'Addons: Processing: Done' return $Addons | Sort-Object name } Write-Verbose "[$scriptName] - [private] - [Addon] - [Initialize-WoWAddon] - Done" #endregion - From [private] - [Addon] - [Initialize-WoWAddon] Write-Verbose "[$scriptName] - [private] - [Addon] - Done" #endregion - From [private] - [Addon] #region - From [private] - [BNetAPI] Write-Verbose "[$scriptName] - [private] - [BNetAPI] - Processing folder" #region - From [private] - [BNetAPI] - [Export-BNetAPISetting] Write-Verbose "[$scriptName] - [private] - [BNetAPI] - [Export-BNetAPISetting] - Importing" function Export-BNetAPISetting { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] param() Write-WoWVerbose 'Export-BNetAPISetting: Export: Start' Get-BNetAPIRegion | Select-Object Region | ConvertTo-Json -EnumsAsStrings | Out-File -FilePath "$Script:WoW_Folder_Cache\BNetAPISettings.json" -Force Write-WoWVerbose 'Export-BNetAPISetting: Export: Done' } Write-Verbose "[$scriptName] - [private] - [BNetAPI] - [Export-BNetAPISetting] - Done" #endregion - From [private] - [BNetAPI] - [Export-BNetAPISetting] #region - From [private] - [BNetAPI] - [Get-BNetAPIUserAccessToken] Write-Verbose "[$scriptName] - [private] - [BNetAPI] - [Get-BNetAPIUserAccessToken] - Importing" function Get-BNetAPIUserAccessToken { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Token Parameter description .PARAMETER Region Parameter description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] param( $Token = $Script:BNetAPI_AccessToken, $Region = $Script:BNetAPI_Settings.Region ) $Body = @{ ':region' = $Region token = $Token } try { $params = @{ Method = 'Post' Uri = "$($Script:BNetAPI_Settings.BNetAPIPath)oauth/check_token" Body = $Body ContentType = 'application/x-www-form-urlencoded' ErrorAction = 'Stop' } $Response = Invoke-RestMethod @params } catch { throw $_ } return $Response } Write-Verbose "[$scriptName] - [private] - [BNetAPI] - [Get-BNetAPIUserAccessToken] - Done" #endregion - From [private] - [BNetAPI] - [Get-BNetAPIUserAccessToken] #region - From [private] - [BNetAPI] - [Get-BNetAPIUserInfo] Write-Verbose "[$scriptName] - [private] - [BNetAPI] - [Get-BNetAPIUserInfo] - Importing" function Get-BNetAPIUserInfo { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Token Parameter description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] param( $Token = $Script:BNetAPI_AccessToken ) $Headers = @{ Authorization = "Bearer $Token" } try { $params = @{ Method = 'Get' Uri = "$($Script:BNetAPI_Settings.BNetAPIPath)oauth/userinfo" Headers = $Headers ContentType = 'application/x-www-form-urlencoded' ErrorAction = 'Stop' } $Response = Invoke-RestMethod @params } catch { throw $_ } return $Response } Write-Verbose "[$scriptName] - [private] - [BNetAPI] - [Get-BNetAPIUserInfo] - Done" #endregion - From [private] - [BNetAPI] - [Get-BNetAPIUserInfo] #region - From [private] - [BNetAPI] - [Get-BNetAPIWoWRealm] Write-Verbose "[$scriptName] - [private] - [BNetAPI] - [Get-BNetAPIWoWRealm] - Importing" function Get-BNetAPIWoWRealm { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] param() Write-WoWVerbose 'Get-BNetAPIWoWRealm: Finding' [Realm[]]$Realms = $null $Headers = @{ 'Battlenet-Namespace' = $Script:BNetAPI_Settings.WoWNameSpace.Dynamic Authorization = "Bearer $Script:BNetAPI_AccessToken" } $APIURI = $Script:BNetAPI_Settings.APIURI $Locale = $Script:BNetAPI_Settings.Locale $RawRealmIndex = Invoke-RestMethod -Method Get -Uri "$($APIURI)data/wow/realm/index?locale=$($Locale)" -Headers $Headers $RawRealmIndex.realms | ForEach-Object -ThrottleLimit 50 -Parallel { $params = @{ Method = 'Get' Uri = "$using:APIURI/data/wow/realm/$($_.id)?namespace=dynamic-eu&locale=$using:Locale" Headers = $using:Headers } Invoke-RestMethod @params } | ForEach-Object { $Realms += [Realm]::new( $_.id, $_.name, $_.region.name, $_.category, $_.locale, $_.timezone, $_.type.name, $_.is_tournament, $_.slug) } return $Realms } Write-Verbose "[$scriptName] - [private] - [BNetAPI] - [Get-BNetAPIWoWRealm] - Done" #endregion - From [private] - [BNetAPI] - [Get-BNetAPIWoWRealm] #region - From [private] - [BNetAPI] - [Import-BNetAPISetting] Write-Verbose "[$scriptName] - [private] - [BNetAPI] - [Import-BNetAPISetting] - Importing" function Import-BNetAPISetting { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] param() Write-WoWVerbose 'Import-BNetAPISetting: Import: Start' $CacheFilePath = "$Script:WoW_Folder_Cache\BNetAPISettings.json" if (Test-Path $CacheFilePath) { $ImportedBNetAPISettings = Get-Content $CacheFilePath | ConvertFrom-Json Write-WoWVerbose "Import-BNetAPISetting: Import: Setting region to $($ImportedBNetAPISettings.Region)" Set-BNetAPIRegion -Region $ImportedBNetAPISettings.Region Write-WoWVerbose 'Import-BNetAPISetting: Import: Done' } else { Write-WoWVerbose 'Import-BNetAPISetting: Import: Nothing to import' } } Write-Verbose "[$scriptName] - [private] - [BNetAPI] - [Import-BNetAPISetting] - Done" #endregion - From [private] - [BNetAPI] - [Import-BNetAPISetting] #region - From [private] - [BNetAPI] - [Initialize-BNetAPI] Write-Verbose "[$scriptName] - [private] - [BNetAPI] - [Initialize-BNetAPI] - Importing" #Force the Invoke-RestMethod PowerShell cmdlet to use TLS 1.2 #[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls13 enum BNetAPIRegion { CN = 0 US = 1 EU = 2 KR = 3 TW = 4 } $Script:BNetAPI_RegionSettings = @( @{ APIURI = 'https://gateway.battlenet.com.cn/' BNetAPIPath = 'https://www.battlenet.com.cn/' LocaleList = @('zh_CN') Locale = 'zh_CN' Region = 'cn' WoWNameSpace = @{ Static = 'static-cn' Dynamic = 'dynamic-cn' Profile = 'profile-cn' } } @{ APIURI = 'https://us.api.blizzard.com/' BNetAPIPath = 'https://us.battle.net/' LocaleList = @('en_US', 'es_MX', 'pt_BR') Locale = 'en_US' Region = 'us' WoWNameSpace = @{ Static = 'static-us' Dynamic = 'dynamic-us' Profile = 'profile-us' } } @{ APIURI = 'https://eu.api.blizzard.com/' BNetAPIPath = 'https://eu.battle.net/' LocaleList = @('en_GB', 'es_ES', 'fr_FR', 'ru_RU', 'de_DE', 'pt_PT', 'it_IT') Locale = 'en_US' Region = 'eu' WoWNameSpace = @{ Static = 'static-eu' Dynamic = 'dynamic-eu' Profile = 'profile-eu' } } @{ APIURI = 'https://kr.api.blizzard.com/' BNetAPIPath = 'https://kr.battle.net/' LocaleList = @('ko_KR') Locale = @('ko_KR') Region = 'kr' WoWNameSpace = @{ Static = 'static-kr' Dynamic = 'dynamic-kr' Profile = 'profile-kr' } } @{ APIURI = 'https://tw.api.blizzard.com/' BNetAPIPath = 'https://tw.battle.net/' LocaleList = @('zh_TW') Locale = @('zh_TW') Region = 'tw' WoWNameSpace = @{ Static = 'static-tw' Dynamic = 'dynamic-tw' Profile = 'profile-tw' } } ) $Script:BNetAPI_ClientID = '<get from secret vault>' $Script:BNetAPI_ClientSecret = '<get from secret vault>' $Script:BNetAPI_Settings = $Script:BNetAPI_RegionSettings[2] Write-Verbose "[$scriptName] - [private] - [BNetAPI] - [Initialize-BNetAPI] - Done" #endregion - From [private] - [BNetAPI] - [Initialize-BNetAPI] #region - From [private] - [BNetAPI] - [New-BNetAPIUserAccessToken] Write-Verbose "[$scriptName] - [private] - [BNetAPI] - [New-BNetAPIUserAccessToken] - Importing" #https://develop.battle.net/documentation/guides/using-oauth/client-credentials-flow function New-BNetAPIUserAccessToken { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER ClientID Parameter description .PARAMETER ClientSecret Parameter description .EXAMPLE An example .NOTES General notes #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSUseShouldProcessForStateChangingFunctions', '', Scope = 'Function', Justification = 'Not changing state, just an object in memory.' )] [CmdletBinding()] param( $ClientID = $Script:BNetAPI_ClientID, $ClientSecret = $Script:BNetAPI_ClientSecret ) $Body = @{ client_id = $ClientID client_secret = $ClientSecret grant_type = 'client_credentials' scope = '' } try { $params = @{ Method = 'Post' Uri = "$($Script:BNetAPI_Settings.BNetAPIPath)oauth/token" Body = $Body ContentType = 'application/x-www-form-urlencoded' ErrorAction = 'Stop' } $Response = Invoke-RestMethod @params } catch { throw $_ } return $Response.access_token } Write-Verbose "[$scriptName] - [private] - [BNetAPI] - [New-BNetAPIUserAccessToken] - Done" #endregion - From [private] - [BNetAPI] - [New-BNetAPIUserAccessToken] Write-Verbose "[$scriptName] - [private] - [BNetAPI] - Done" #endregion - From [private] - [BNetAPI] #region - From [private] - [Character] Write-Verbose "[$scriptName] - [private] - [Character] - Processing folder" #region - From [private] - [Character] - [PowerType] Write-Verbose "[$scriptName] - [private] - [Character] - [PowerType] - Processing folder" #region - From [private] - [Character] - [PowerType] - [Export-WoWPowerType] Write-Verbose "[$scriptName] - [private] - [Character] - [PowerType] - [Export-WoWPowerType] - Importing" function Export-WoWPowerType { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] param () Get-WoWPowerType | ConvertTo-Json -EnumsAsStrings | Out-File -FilePath "$Script:WoW_Folder_Cache\PowerType.json" -Force } Write-Verbose "[$scriptName] - [private] - [Character] - [PowerType] - [Export-WoWPowerType] - Done" #endregion - From [private] - [Character] - [PowerType] - [Export-WoWPowerType] #region - From [private] - [Character] - [PowerType] - [Import-WoWPowerType] Write-Verbose "[$scriptName] - [private] - [Character] - [PowerType] - [Import-WoWPowerType] - Importing" function Import-WoWPowerType { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> $CacheFilePath = "$Script:WoW_Folder_Cache\PowerType.json" if (Test-Path $CacheFilePath) { $ImportedPowerTypes = Get-Content $CacheFilePath | ConvertFrom-Json foreach ($ImportedPowerType in $ImportedPowerTypes) { [PowerType]::new() } } else { Write-WoWVerbose 'Import-WoWCharacter: Nothing to import' } } Write-Verbose "[$scriptName] - [private] - [Character] - [PowerType] - [Import-WoWPowerType] - Done" #endregion - From [private] - [Character] - [PowerType] - [Import-WoWPowerType] #region - From [private] - [Character] - [PowerType] - [Update-WoWPowerType] Write-Verbose "[$scriptName] - [private] - [Character] - [PowerType] - [Update-WoWPowerType] - Importing" function Update-WoWPowerType { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSUseShouldProcessForStateChangingFunctions', '', Scope = 'Function', Justification = 'Not changing state, just an object in memory.' )] [CmdletBinding()] param() [PowerType[]]$PowerTypes = $null $Headers = @{ 'Battlenet-Namespace' = $Script:BNetAPI_Settings.WoWNameSpace.Static Authorization = "Bearer $Script:BNetAPI_AccessToken" } $APIURI = $Script:BNetAPI_Settings.APIURI $Locale = $Script:BNetAPI_Settings.Locale Write-WoWVerbose 'Update-WoWPowerTypes: Finding PowerTypes online' $PowerTypeIndex = Invoke-RestMethod -Method Get -Uri "$($APIURI)data/wow/power-type/index?locale=$Locale" -Headers $Headers $PowerTypeIndex.power_types | ForEach-Object -Parallel { Invoke-RestMethod -Method Get -Uri "$($using:APIURI)data/wow/power-type/$($_.id)?&locale=$using:Locale" -Headers $using:Headers } | ForEach-Object { $PowerTypes += [PowerType]::new($_.id, $_.name) } return $PowerTypes } Write-Verbose "[$scriptName] - [private] - [Character] - [PowerType] - [Update-WoWPowerType] - Done" #endregion - From [private] - [Character] - [PowerType] - [Update-WoWPowerType] Write-Verbose "[$scriptName] - [private] - [Character] - [PowerType] - Done" #endregion - From [private] - [Character] - [PowerType] #region - From [private] - [Character] - [Export-WoWCharacter] Write-Verbose "[$scriptName] - [private] - [Character] - [Export-WoWCharacter] - Importing" function Export-WoWCharacter { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> Get-WoWCharacter | ConvertTo-Json -EnumsAsStrings | Out-File -FilePath "$Script:WoW_Folder_Cache\Characters.json" -Force } Write-Verbose "[$scriptName] - [private] - [Character] - [Export-WoWCharacter] - Done" #endregion - From [private] - [Character] - [Export-WoWCharacter] #region - From [private] - [Character] - [Import-WoWCharacter] Write-Verbose "[$scriptName] - [private] - [Character] - [Import-WoWCharacter] - Importing" function Import-WoWCharacter { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> $CacheFilePath = "$Script:WoW_Folder_Cache\Characters.json" if (Test-Path $CacheFilePath) { $ImportedCharacters = Get-Content $CacheFilePath | ConvertFrom-Json foreach ($ImportedCharacter in $ImportedCharacters) { $Character = [Character]( $Script:WoW_Characters | Where-Object { ($_.Realm.Name -match $ImportedCharacter.Realm.Name) -and ($_.Name -match $ImportedCharacter.Name) } | Select-Object -First 1) $Character.ID = $ImportedCharacter.ID $Character.Gender = $ImportedCharacter.Gender $Character.Faction = $ImportedCharacter.Faction $Character.Race = $ImportedCharacter.Race $Character.IsMainForClass = $ImportedCharacter.IsMainForClass $Character.IsMain = $ImportedCharacter.IsMain $Character.Level = $ImportedCharacter.Level $Character.Guild = $ImportedCharacter.Guild $Character.AchievementPoints = $ImportedCharacter.AchievementPoints $Character.LastPlayed = [datetime]$ImportedCharacter.LastPlayed $Character.averageItemLevel = $ImportedCharacter.averageItemLevel $Character.averageItemLevelEquipped = $ImportedCharacter.averageItemLevelEquipped $Character.Gold = $ImportedCharacter.Gold $Character.PlayedLevel = (New-TimeSpan).Add($ImportedCharacter.PlayedLevel.Ticks) $Character.PlayedTotal = (New-TimeSpan).Add($ImportedCharacter.PlayedTotal.Ticks) $Character.isResting = $ImportedCharacter.isResting $Character.ArtifactLevel = $ImportedCharacter.ArtifactLevel $Character.ArtifactProgress = $ImportedCharacter.ArtifactProgress $Character.Zone = $ImportedCharacter.Zone $Character.Warmode = $ImportedCharacter.Warmode $Character.HasNewMail = $ImportedCharacter.HasNewMail $Character.Durability = $ImportedCharacter.Durability } } else { Write-WoWVerbose 'Import-WoWCharacter: Nothing to import' } } Write-Verbose "[$scriptName] - [private] - [Character] - [Import-WoWCharacter] - Done" #endregion - From [private] - [Character] - [Import-WoWCharacter] #region - From [private] - [Character] - [Initialize-WoWCharacter] Write-Verbose "[$scriptName] - [private] - [Character] - [Initialize-WoWCharacter] - Importing" function Initialize-WoWCharacter { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER WoWAccountsFolderPath Parameter description .EXAMPLE An example .NOTES General notes #> [Cmdletbinding()] param( $WoWAccountsFolderPath = $Script:WoW_Folder_Accounts ) [Character[]]$Characters = $null Write-WoWVerbose 'Characters: Finding' $AccountFolders = $WoWAccountsFolderPath | Get-ChildItem -Directory | Where-Object Name -NE SavedVariables $RealmFolders = $AccountFolders | Get-ChildItem -Directory | Where-Object Name -NE SavedVariables $CharFolders = $RealmFolders | Get-ChildItem -Directory | Where-Object Name -NE SavedVariables | Sort-Object name Write-WoWVerbose "Characters: Found $($CharFolders.count)" Write-WoWVerbose 'Characters: Processing' $i = 0 foreach ($CharFolder in $CharFolders) { $i++ $Status = "$i/$($CharFolders.count)" Write-WoWVerbose "Characters: Processing: $Status $($CharFolder.Name)" $Char = [Character]::new() $Char.FolderPath = $CharFolder $CharFolderCN = ($CharFolder -split ('\\')) $CharName = $CharFolderCN[-1] $CharRealmName = $CharFolderCN[-2] $CharAccountName = $CharFolderCN[-3] $Char.Name = $CharName $Char.Realm = $Script:WoW_Realms | Where-Object Name -EQ $CharRealmName $Char.Account = $Script:WoW_Accounts | Where-Object Name -EQ $CharAccountName $Char.Account.Characters += $Char $Char.IsMainForClass = $false $Char.IsMain = $false $Char.SettingsFolderPath = "$($Char.FolderPath)\SavedVariables" $Char.AddOnsFilePath = "$($Char.FolderPath)\AddOns.txt" $Char.BindingsCachePath = "$($Char.FolderPath)\bindings-cache.wtf" $Char.ConfigCachePath = "$($Char.FolderPath)\config-cache.wtf" $Char.MacrosCachePath = "$($Char.FolderPath)\macros-cache.txt" $Characters += $Char Write-WoWVerbose "Characters: Processing: $Status $($CharFolder.Name): Done" } Write-WoWVerbose 'Characters: Processing: Done' return $Characters | Sort-Object name } Write-Verbose "[$scriptName] - [private] - [Character] - [Initialize-WoWCharacter] - Done" #endregion - From [private] - [Character] - [Initialize-WoWCharacter] Write-Verbose "[$scriptName] - [private] - [Character] - Done" #endregion - From [private] - [Character] #region - From [private] - [Core] Write-Verbose "[$scriptName] - [private] - [Core] - Processing folder" #region - From [private] - [Core] - [Find-WoWFolder] Write-Verbose "[$scriptName] - [private] - [Core] - [Find-WoWFolder] - Importing" function Find-WoWFolder { <# .SYNOPSIS Find WoW (retail) folder .DESCRIPTION Finds WoW (retail) folder, by first checking for the default location, then looking for all folders with a WoW.exe file. User is prompted for possible location where WoW.exe is found. .EXAMPLE Get-WoWFolder #> [Cmdletbinding()] [OutputType([System.IO.DirectoryInfo])] param( $Path = 'C:\Program Files (x86)\World of Warcraft\_retail_' ) $DefaultPath = 'C:\Program Files (x86)\World of Warcraft\_retail_' Write-WoWVerbose 'Looking for WoW folders' if (Test-Path -Path $Path) { Write-WoWVerbose "Found $Path" Write-WoWVerbose "Looking for WoW.exe in $Path" $WoWFile = Get-ChildItem -Path $Path -Filter Wow.exe -File -Recurse -ErrorAction SilentlyContinue if ($WoWFile) { Write-WoWVerbose "Found WoW.exe in $($WoWFile.Directory)" return $WoWFile.Directory } } elseif (Test-Path -Path $DefaultPath) { Write-WoWVerbose "Found $DefaultPath" Write-WoWVerbose "Looking for WoW.exe in $DefaultPath" $WoWFile = Get-ChildItem -Path $DefaultPath -Filter Wow.exe -File -Recurse -ErrorAction SilentlyContinue if ($WoWFile) { Write-WoWVerbose "Found WoW.exe in $($WoWFile.Directory)" return $WoWFile.Directory } } else { $Disks = Get-Volume | Where-Object { ($null -ne $_.DriveLetter) -and ($_.DriveType -eq 'Fixed') } | Select-Object -ExpandProperty DriveLetter | ForEach-Object { Get-Item -Path "$_`:\" } $WoWFolders = $Disks | Get-ChildItem -Recurse -ErrorAction SilentlyContinue -Include 'wow.exe' | Select-Object -ExpandProperty DirectoryName if ($WoWFolders.count -gt 1) { Write-WoWVerbose 'Multiple instances of WoW detected:' $i = 0 # $WoWFolder = $WoWFolders[0] foreach ($WoWFolder in $WoWFolders) { Write-WoWVerbose "$i - $WoWFolder" $i++ } $Selection = Read-Host -Prompt 'Select WoW instance: ' } else { return $WoWFolders } return $WoWFolders[$Selection] } } Write-Verbose "[$scriptName] - [private] - [Core] - [Find-WoWFolder] - Done" #endregion - From [private] - [Core] - [Find-WoWFolder] #region - From [private] - [Core] - [Get-WoWCacheFolder] Write-Verbose "[$scriptName] - [private] - [Core] - [Get-WoWCacheFolder] - Importing" function Get-WoWCacheFolder { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER FolderPath Parameter description .EXAMPLE An example .NOTES General notes #> [Cmdletbinding()] param( [string] [Parameter(Mandatory)] $FolderPath ) if (Test-Path $FolderPath) { Write-WoWVerbose 'Folder exists, returning the object' $FolderObj = Get-Item -Path $FolderPath } else { Write-WoWVerbose "Folder doen't exists, creating folder" $FolderObj = New-Item -Path $FolderPath -ItemType Directory -Force Write-WoWVerbose 'Folder created' } return $FolderObj } Write-Verbose "[$scriptName] - [private] - [Core] - [Get-WoWCacheFolder] - Done" #endregion - From [private] - [Core] - [Get-WoWCacheFolder] #region - From [private] - [Core] - [Write-WoWVerbose] Write-Verbose "[$scriptName] - [private] - [Core] - [Write-WoWVerbose] - Importing" function Write-WoWVerbose { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Message Parameter description .EXAMPLE An example .NOTES General notes #> [Cmdletbinding()] param( [string] $Message ) <# $CallStack = (Get-PSCallStack).Command | Select-Object -SkipLast 1 if ($CallStack.count -gt 1) { $CallStack = $CallStack | Select-Object -Skip 1 $CallStack = $CallStack | Select-Object -Skip 1 | Select-Object -First 1 [array]::Reverse($CallStack) $CallStack = $CallStack -join " > " } Write-Verbose "[$(Get-Date -Format $Script:WoW_DateFormat)]: $CallStack`: $Message" #> Write-Verbose "[$(Get-Date -Format $Script:WoW_DateFormat)]: $Message" } Write-Verbose "[$scriptName] - [private] - [Core] - [Write-WoWVerbose] - Done" #endregion - From [private] - [Core] - [Write-WoWVerbose] #region - From [private] - [Core] - [Write-WoWWarning] Write-Verbose "[$scriptName] - [private] - [Core] - [Write-WoWWarning] - Importing" function Write-WoWWarning { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Message Parameter description .EXAMPLE An example .NOTES General notes #> [Cmdletbinding()] param( [Parameter(Mandatory)] [string] $Message ) $CallStack = (Get-PSCallStack).Command | Select-Object -SkipLast 1 if ($CallStack.count -gt 1) { $CallStack = $CallStack | Select-Object -Skip 1 [array]::Reverse($CallStack) } Write-Warning "[$(Get-Date -Format $Script:DateFormat)]: $CallStack`: $Message" } Write-Verbose "[$scriptName] - [private] - [Core] - [Write-WoWWarning] - Done" #endregion - From [private] - [Core] - [Write-WoWWarning] Write-Verbose "[$scriptName] - [private] - [Core] - Done" #endregion - From [private] - [Core] #region - From [private] - [Realm] Write-Verbose "[$scriptName] - [private] - [Realm] - Processing folder" #region - From [private] - [Realm] - [Export-WoWRealm] Write-Verbose "[$scriptName] - [private] - [Realm] - [Export-WoWRealm] - Importing" function Export-WoWRealm { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> Get-WoWRealm | ConvertTo-Json -EnumsAsStrings | Out-File -FilePath "$Script:WoW_Folder_Cache\Realms.json" -Force } Write-Verbose "[$scriptName] - [private] - [Realm] - [Export-WoWRealm] - Done" #endregion - From [private] - [Realm] - [Export-WoWRealm] #region - From [private] - [Realm] - [Import-WoWRealm] Write-Verbose "[$scriptName] - [private] - [Realm] - [Import-WoWRealm] - Importing" function Import-WoWRealm { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> [Realm[]]$Realms = $null $CacheFilePath = "$Script:WoW_Folder_Cache\Realms.json" if (Test-Path $CacheFilePath) { $ImportedRealms = Get-Content $CacheFilePath | ConvertFrom-Json #$ImportedRealm = $ImportedRealms[0] foreach ($ImportedRealm in $ImportedRealms) { $Realm = [Realm]::new() $Realm.ID = $ImportedRealm.ID $Realm.Region = $ImportedRealm.Region $Realm.Category = $ImportedRealm.Category $Realm.Locale = $ImportedRealm.Locale $Realm.Timezone = $ImportedRealm.Timezone $Realm.Type = $ImportedRealm.Type $Realm.IsTournament = $ImportedRealm.IsTournament $Realm.Slug = $ImportedRealm.Slug $Realms += $Realm } return $Realms } else { Write-WoWVerbose 'Import-WoWRealm: Nothing to import' return } } Write-Verbose "[$scriptName] - [private] - [Realm] - [Import-WoWRealm] - Done" #endregion - From [private] - [Realm] - [Import-WoWRealm] #region - From [private] - [Realm] - [Initialize-WoWRealm] Write-Verbose "[$scriptName] - [private] - [Realm] - [Initialize-WoWRealm] - Importing" function Initialize-WoWRealm { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER WoWAccountsFolderPath Parameter description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] [OutputType([Realm[]])] param( $WoWAccountsFolderPath = $Script:WoW_Folder_Accounts ) [Realm[]]$Realms = $null Write-WoWVerbose 'Realms: Finding' $AccountFolders = $WoWAccountsFolderPath | Get-ChildItem -Directory | Where-Object Name -NE SavedVariables $RealmNames = $AccountFolders | Get-ChildItem -Directory | Where-Object Name -NE SavedVariables | Select-Object -ExpandProperty Name -Unique Write-WoWVerbose "Realms: Found $($RealmNames.count)" Write-WoWVerbose 'Realms: Processing' $i = 0 # $AccountFolder = $AccountFolders | Where-Object name -match "Catchius" foreach ($RealmName in $RealmNames) { $i++ $Status = "$i/$($RealmNames.count)" Write-WoWVerbose "Realms: Processing: $Status $RealmName" $Realm = [Realm]::new($RealmName) $Realms += $Realm Write-WoWVerbose "Realms: Processing: $Status $($RealmName): Done" } Write-WoWVerbose 'Realms: Processing: Done' return $Realms | Sort-Object name } Write-Verbose "[$scriptName] - [private] - [Realm] - [Initialize-WoWRealm] - Done" #endregion - From [private] - [Realm] - [Initialize-WoWRealm] #region - From [private] - [Realm] - [Update-WoWRealm] Write-Verbose "[$scriptName] - [private] - [Realm] - [Update-WoWRealm] - Importing" function Update-WoWRealm { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSUseShouldProcessForStateChangingFunctions', '', Scope = 'Function', Justification = 'Not changing state, just an object in memory.' )] [CmdletBinding()] param() [Realm[]]$Realms = $null $Headers = @{ 'Battlenet-Namespace' = $Script:BNetAPI_Settings.WoWNameSpace.Dynamic Authorization = "Bearer $Script:BNetAPI_AccessToken" } $APIURI = $Script:BNetAPI_Settings.APIURI $Locale = $Script:BNetAPI_Settings.Locale #$ApplicableRealms = $Script:WoW_Realms.Name Write-WoWVerbose 'Update-WoWRealm: Finding realms online' $RealmIndex = Invoke-RestMethod -Method Get -Uri "$($APIURI)data/wow/realm/index?locale=$Locale" -Headers $Headers $RealmsToUpdate = $RealmIndex.realms # | Where-Object Name -In -Value $ApplicableRealms $RealmsToUpdate | ForEach-Object -ThrottleLimit 50 -Parallel { Invoke-RestMethod -Method Get -Uri "$($using:APIURI)data/wow/realm/$($_.id)?locale=$using:Locale" -Headers $using:Headers } | ForEach-Object { $Realms += [Realm]::new( $_.id, $_.name, $_.region.name, $_.category, $_.locale, $_.timezone, $_.type.name, $_.is_tournament, $_.slug) } return $Realms } Write-Verbose "[$scriptName] - [private] - [Realm] - [Update-WoWRealm] - Done" #endregion - From [private] - [Realm] - [Update-WoWRealm] Write-Verbose "[$scriptName] - [private] - [Realm] - Done" #endregion - From [private] - [Realm] Write-Verbose "[$scriptName] - [private] - Done" #endregion - From [private] #region - From [public] Write-Verbose "[$scriptName] - [public] - Processing folder" #region - From [public] - [Account] Write-Verbose "[$scriptName] - [public] - [Account] - Processing folder" #region - From [public] - [Account] - [Get-WoWAccount] Write-Verbose "[$scriptName] - [public] - [Account] - [Get-WoWAccount] - Importing" function Get-WoWAccount { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Name Parameter description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] param ( [String] $Name ) return $Script:WoW_Accounts | Where-Object Name -Match $Name } Write-Verbose "[$scriptName] - [public] - [Account] - [Get-WoWAccount] - Done" #endregion - From [public] - [Account] - [Get-WoWAccount] #region - From [public] - [Account] - [Set-WoWAccount] Write-Verbose "[$scriptName] - [public] - [Account] - [Set-WoWAccount] - Importing" function Set-WoWAccount { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Name Parameter description .PARAMETER IsMain Parameter description .EXAMPLE An example .NOTES General notes #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSUseShouldProcessForStateChangingFunctions', '', Scope = 'Function', Justification = 'Not changing state, just an object in memory.' )] [cmdletbinding()] param( [parameter(mandatory)] [String] $Name, [bool] $IsMain ) [Account]$Account = Get-WoWAccount | Where-Object Name -Match $Name $Account.IsMain = $IsMain Export-WoWAccount } Write-Verbose "[$scriptName] - [public] - [Account] - [Set-WoWAccount] - Done" #endregion - From [public] - [Account] - [Set-WoWAccount] #region - From [public] - [Account] - [Show-WoWAccount] Write-Verbose "[$scriptName] - [public] - [Account] - [Show-WoWAccount] - Importing" function Show-WoWAccount { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] [OutputType([void])] param() $Script:WoW_Account | Out-GridView -Title 'WoWManager - List WoW Accounts' } Write-Verbose "[$scriptName] - [public] - [Account] - [Show-WoWAccount] - Done" #endregion - From [public] - [Account] - [Show-WoWAccount] Write-Verbose "[$scriptName] - [public] - [Account] - Done" #endregion - From [public] - [Account] #region - From [public] - [Addon] Write-Verbose "[$scriptName] - [public] - [Addon] - Processing folder" #region - From [public] - [Addon] - [Get-WoWAddon] Write-Verbose "[$scriptName] - [public] - [Addon] - [Get-WoWAddon] - Importing" function Get-WoWAddon { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Name Parameter description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] [OutputType([Addon[]])] param( [String] $Name ) return $Script:WoW_Addons | Where-Object Name -Match $Name } Write-Verbose "[$scriptName] - [public] - [Addon] - [Get-WoWAddon] - Done" #endregion - From [public] - [Addon] - [Get-WoWAddon] #region - From [public] - [Addon] - [Select-WoWAddon] Write-Verbose "[$scriptName] - [public] - [Addon] - [Select-WoWAddon] - Importing" function Select-WoWAddon { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] [OutputType([Addon[]])] param() return $Script:WoW_Addons | Out-GridView -Title 'WoWManager - Installed WoW Addons' -OutputMode Multiple } Write-Verbose "[$scriptName] - [public] - [Addon] - [Select-WoWAddon] - Done" #endregion - From [public] - [Addon] - [Select-WoWAddon] #region - From [public] - [Addon] - [Show-WoWAddon] Write-Verbose "[$scriptName] - [public] - [Addon] - [Show-WoWAddon] - Importing" function Show-WoWAddon { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] [OutputType([void])] param() $Script:WoW_Addons | Out-GridView -Title 'WoWManager - Installed WoW Addons' } Write-Verbose "[$scriptName] - [public] - [Addon] - [Show-WoWAddon] - Done" #endregion - From [public] - [Addon] - [Show-WoWAddon] Write-Verbose "[$scriptName] - [public] - [Addon] - Done" #endregion - From [public] - [Addon] #region - From [public] - [BNetAPI] Write-Verbose "[$scriptName] - [public] - [BNetAPI] - Processing folder" #region - From [public] - [BNetAPI] - [Get-BNetAPIRegion] Write-Verbose "[$scriptName] - [public] - [BNetAPI] - [Get-BNetAPIRegion] - Importing" function Get-BNetAPIRegion { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] param() return $Script:BNetAPI_Settings } Write-Verbose "[$scriptName] - [public] - [BNetAPI] - [Get-BNetAPIRegion] - Done" #endregion - From [public] - [BNetAPI] - [Get-BNetAPIRegion] #region - From [public] - [BNetAPI] - [Set-BNetAPIRegion] Write-Verbose "[$scriptName] - [public] - [BNetAPI] - [Set-BNetAPIRegion] - Importing" function Set-BNetAPIRegion { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Region Parameter description .EXAMPLE An example .NOTES General notes #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSUseShouldProcessForStateChangingFunctions', '', Scope = 'Function', Justification = 'Not changing state, just an object in memory.' )] [CmdletBinding()] param( [BNetAPIRegion] $Region ) $Script:BNetAPI_Settings = $Script:BNetAPI_RegionSettings[$Region] Export-BNetAPISetting } Write-Verbose "[$scriptName] - [public] - [BNetAPI] - [Set-BNetAPIRegion] - Done" #endregion - From [public] - [BNetAPI] - [Set-BNetAPIRegion] Write-Verbose "[$scriptName] - [public] - [BNetAPI] - Done" #endregion - From [public] - [BNetAPI] #region - From [public] - [Character] Write-Verbose "[$scriptName] - [public] - [Character] - Processing folder" #region - From [public] - [Character] - [PowerType] Write-Verbose "[$scriptName] - [public] - [Character] - [PowerType] - Processing folder" #region - From [public] - [Character] - [PowerType] - [Get-WoWPowerType] Write-Verbose "[$scriptName] - [public] - [Character] - [PowerType] - [Get-WoWPowerType] - Importing" function Get-WoWPowerType { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Name Parameter description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] param ( [String] $Name ) return $Script:WoW_PowerTypes | Where-Object Name -Match $Name } Write-Verbose "[$scriptName] - [public] - [Character] - [PowerType] - [Get-WoWPowerType] - Done" #endregion - From [public] - [Character] - [PowerType] - [Get-WoWPowerType] Write-Verbose "[$scriptName] - [public] - [Character] - [PowerType] - Done" #endregion - From [public] - [Character] - [PowerType] #region - From [public] - [Character] - [Get-WoWCharacter] Write-Verbose "[$scriptName] - [public] - [Character] - [Get-WoWCharacter] - Importing" function Get-WoWCharacter { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Name Parameter description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] param ( [String] $Name ) return $Script:WoW_Characters | Where-Object Name -Match $Name } Write-Verbose "[$scriptName] - [public] - [Character] - [Get-WoWCharacter] - Done" #endregion - From [public] - [Character] - [Get-WoWCharacter] #region - From [public] - [Character] - [Set-WoWCharacter] Write-Verbose "[$scriptName] - [public] - [Character] - [Set-WoWCharacter] - Importing" function Set-WoWCharacter { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Name Parameter description .PARAMETER Realm Parameter description .PARAMETER IsMain Parameter description .PARAMETER IsMainForClass Parameter description .PARAMETER ClassName Parameter description .EXAMPLE An example .NOTES General notes #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSUseShouldProcessForStateChangingFunctions', '', Scope = 'Function', Justification = 'Not changing state, just an object in memory.' )] [Cmdletbinding()] param( [parameter(mandatory)] [String] $Name, [parameter(mandatory)] [String] $Realm, [bool] $IsMain, [bool] $IsMainForClass, [string] $ClassName ) $Character = [Character]($Script:WoW_Characters | Where-Object { ($_.Realm.Name -match $Realm) -and ($_.Name -match $Name) } | Select-Object -First 1) if ($Character.count -eq 1) { if ($PSBoundParameters.ContainsKey('IsMain')) { $Character.IsMain = $IsMain } if ($PSBoundParameters.ContainsKey('IsMainForClass')) { $Character.IsMainForClass = $IsMainForClass } if ($PSBoundParameters.ContainsKey('ClassName')) { $Character.Class = $Script:WoW_Classes | Where-Object Name -Match $ClassName } Export-WoWCharacter } } Write-Verbose "[$scriptName] - [public] - [Character] - [Set-WoWCharacter] - Done" #endregion - From [public] - [Character] - [Set-WoWCharacter] Write-Verbose "[$scriptName] - [public] - [Character] - Done" #endregion - From [public] - [Character] #region - From [public] - [Core] Write-Verbose "[$scriptName] - [public] - [Core] - Processing folder" #region - From [public] - [Core] - [Get-WoWFolder] Write-Verbose "[$scriptName] - [public] - [Core] - [Get-WoWFolder] - Importing" function Get-WoWFolder { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Folder Parameter description .EXAMPLE An example .NOTES General notes #> param( [ValidateSet('All', 'Root', 'Account', 'WTF', 'Cache')] [String] $Folder = 'Root' ) switch ($Folder) { 'All' { return Get-Variable -Scope Script -Name WoW_Folder_* | Sort-Object Value } 'Root' { return $Script:WoW_Folder_Root } 'Account' { return $Script:WoW_Folder_Account } 'WTF' { return $Script:WoW_Folder_WTF } 'Cache' { return $Script:WoW_Folder_Cache } default {} } } Write-Verbose "[$scriptName] - [public] - [Core] - [Get-WoWFolder] - Done" #endregion - From [public] - [Core] - [Get-WoWFolder] #region - From [public] - [Core] - [Invoke-WoWManager] Write-Verbose "[$scriptName] - [public] - [Core] - [Invoke-WoWManager] - Importing" function Invoke-WoWManager { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] param() #Common date format $Script:WoW_DateFormat = 'yyyyMMdd-HHmmss' $Script:WoW_Folder_Root = Find-WoWFolder $Script:WoW_Folder_WTF = Get-Item "$Script:WoW_Folder_Root\WTF" $Script:WoW_Folder_Accounts = Get-Item "$Script:WoW_Folder_WTF\Account" $Script:WoW_Folder_Addons = Get-Item "$Script:WoW_Folder_Root\Interface\addons" #Location for saving data $Script:WoW_Folder_Cache = Get-WoWCacheFolder -FolderPath "$env:appdata\WoWManager" #Preparing connection with BNet API $Script:BNetAPI_AccessToken = New-BNetAPIUserAccessToken Import-BNetAPISetting Export-BNetAPISetting #Collecting info from the game folder [Addon[]]$Script:WoW_Addons = Initialize-WoWAddon -WoWAddonsFolderPath $Script:WoW_Folder_Addons [Account[]]$Script:WoW_Accounts = Initialize-WoWAccount -WoWAccountsFolderPath $Script:WoW_Folder_Accounts Import-WoWAccount Export-WoWAccount #[Realm[]]$Script:WoW_Realms = Initialize-WoWRealm -WoWAccountsFolderPath $Script:WoW_Folder_Accounts [Realm[]]$Script:WoW_Realms = Import-WoWRealm Export-WoWRealm [PowerType[]]$Script:WoW_PowerTypes = Update-WoWPowerTypes [Character[]]$Script:WoW_Characters = Initialize-WoWCharacter -WoWAccountsFolderPath $Script:WoW_Folder_Accounts Import-WoWCharacter Export-WoWCharacter } Write-Verbose "[$scriptName] - [public] - [Core] - [Invoke-WoWManager] - Done" #endregion - From [public] - [Core] - [Invoke-WoWManager] Write-Verbose "[$scriptName] - [public] - [Core] - Done" #endregion - From [public] - [Core] #region - From [public] - [Realm] Write-Verbose "[$scriptName] - [public] - [Realm] - Processing folder" #region - From [public] - [Realm] - [Get-WoWRealm] Write-Verbose "[$scriptName] - [public] - [Realm] - [Get-WoWRealm] - Importing" function Get-WoWRealm { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Name Parameter description .EXAMPLE An example .NOTES General notes #> [CmdletBinding()] [OutputType([Addon[]])] param( [String] $Name ) return $Script:WoW_Realms | Where-Object Name -Match $Name } Write-Verbose "[$scriptName] - [public] - [Realm] - [Get-WoWRealm] - Done" #endregion - From [public] - [Realm] - [Get-WoWRealm] #region - From [public] - [Realm] - [Update-WoWRealm] Write-Verbose "[$scriptName] - [public] - [Realm] - [Update-WoWRealm] - Importing" function Update-WoWRealm { <# .SYNOPSIS Short description .DESCRIPTION Long description .EXAMPLE An example .NOTES General notes #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSUseShouldProcessForStateChangingFunctions', '', Scope = 'Function', Justification = 'Not changing state, just an object in memory.' )] [CmdletBinding()] param() [Realm[]]$Realms = $null $Headers = @{ 'Battlenet-Namespace' = $Script:BNetAPI_Settings.WoWNameSpace.Dynamic Authorization = "Bearer $Script:BNetAPI_AccessToken" } $APIURI = $Script:BNetAPI_Settings.APIURI $Locale = $Script:BNetAPI_Settings.Locale #$ApplicableRealms = $Script:WoW_Realms.Name Write-WoWVerbose 'Update-WoWRealm: Finding realms online' $RealmIndex = Invoke-RestMethod -Method Get -Uri "$($APIURI)data/wow/realm/index?locale=$Locale" -Headers $Headers $RealmsToUpdate = $RealmIndex.realms # | Where-Object Name -In -Value $ApplicableRealms $RealmsToUpdate | ForEach-Object -ThrottleLimit 50 -Parallel { Invoke-RestMethod -Method Get -Uri "$($using:APIURI)data/wow/realm/$($_.id)?locale=$using:Locale" -Headers $using:Headers } | ForEach-Object { $Realms += [Realm]::new( $_.id, $_.name, $_.region.name, $_.category, $_.locale, $_.timezone, $_.type.name, $_.is_tournament, $_.slug) } return $Realms } Write-Verbose "[$scriptName] - [public] - [Realm] - [Update-WoWRealm] - Done" #endregion - From [public] - [Realm] - [Update-WoWRealm] Write-Verbose "[$scriptName] - [public] - [Realm] - Done" #endregion - From [public] - [Realm] Write-Verbose "[$scriptName] - [public] - Done" #endregion - From [public] # Get the internal TypeAccelerators class to use its static methods. $TypeAcceleratorsClass = [psobject].Assembly.GetType( 'System.Management.Automation.TypeAccelerators' ) # Ensure none of the types would clobber an existing type accelerator. # If a type accelerator with the same name exists, throw an exception. $ExistingTypeAccelerators = $TypeAcceleratorsClass::Get # Define the types to export with type accelerators. $ExportableEnums = @( [Role] [Faction] [Gender] [BNetAPIRegion] ) $ExportableEnums | Foreach-Object { Write-Verbose "Exporting enum '$($_.FullName)'." } foreach ($Type in $ExportableEnums) { if ($Type.FullName -in $ExistingTypeAccelerators.Keys) { Write-Warning "Enum already exists [$($Type.FullName)]. Skipping." } else { Write-Verbose "Importing enum '$Type'." $TypeAcceleratorsClass::Add($Type.FullName, $Type) } } $ExportableClasses = @( [Account] [Addon] [AzeriteEssence] [PlayableClass] [Character] [Currency] [PowerType] [Race] [Realm] [Specialization] ) $ExportableClasses | Foreach-Object { Write-Verbose "Exporting class '$($_.FullName)'." } foreach ($Type in $ExportableClasses) { if ($Type.FullName -in $ExistingTypeAccelerators.Keys) { Write-Warning "Class already exists [$($Type.FullName)]. Skipping." } else { Write-Verbose "Importing class '$Type'." $TypeAcceleratorsClass::Add($Type.FullName, $Type) } } # Remove type accelerators when the module is removed. $MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = { foreach ($Type in ($ExportableEnums + $ExportableClasses)) { $TypeAcceleratorsClass::Remove($Type.FullName) } }.GetNewClosure() $exports = @{ Alias = '*' Cmdlet = '' Function = @( 'Get-WoWAccount' 'Set-WoWAccount' 'Show-WoWAccount' 'Get-WoWAddon' 'Select-WoWAddon' 'Show-WoWAddon' 'Get-BNetAPIRegion' 'Set-BNetAPIRegion' 'Get-WoWPowerType' 'Get-WoWCharacter' 'Set-WoWCharacter' 'Get-WoWFolder' 'Invoke-WoWManager' 'Get-WoWRealm' 'Update-WoWRealm' ) Variable = '' } Export-ModuleMember @exports |