Home

Wednesday, July 18, 2018

PowerShell + Fiddler - Learning - Entry 2

INFO:
Playing around with grabbing information about local player accounts through fiddler proxy.

TODO:
I need to write a fiddler script that can be called with auto-responder to save out the header and body of a specified Host call to a chosen directory location.

Keywords:
PowerShell, v5,
Fiddler, xbl, xbox, live, application, windows 10, pc,
regex, Regular Expression, matches, match
look forward, look backward, lazy, greedy,

Resources:
#Personal Note: Source code and resource sights
#https://blogs.msdn.microsoft.com/fiddler/2011/12/10/revisiting-fiddler-and-win8-immersive-applications/
#https://docs.microsoft.com/en-us/windows/uwp/xbox-live/using-xbox-live/troubleshooting/how-to-set-up-fiddler-for-debugging
#https://docs.microsoft.com/en-us/windows/uwp/xbox-apps/uwp-fiddler
#https://docs.microsoft.com/en-us/windows/uwp/xbox-apps/uwp-fiddler

#As seen in xbox + fiddler microsoft documentation
#LoopBack: netsh winhttp set proxy 127.0.0.1:8888 "<-loopback>"


CODE:
$SourceFolder = "$env:USERPROFILE\Desktop"
$XblTitlehub = "40_.json"
$XblSessiondirectory = "45_Response.txt"
$XblAccounts = "19_.json"
$XblProfile = "9_Response.txt"


#========================== peoplehub.xboxlive.com ==========================#
###\ Response\Body


#========================== sessiondirectory.xboxlive.com ==========================#
###\ \ Response\Header or Entire R*
#(?<=gamertag=)(.*)(?=;)
#(?<='string') Look at end of string
#(?='string') Exclude at string

$patternA = "(?<=gamertag=)"
$Match = ".*"
$PatternB = "(?=;)"
$pattern = "$patternA$Match$PatternB"

$sessiond = Get-Content "$SourceFolder\$XblSessiondirectory"
$gamerTag = [Regex]::Matches($sessiond, $pattern).groups[0].value

$pattern = "(?<=sandbox=).*?(?=,)"
$sandBox = [Regex]::Matches($sessiond, $pattern).groups[0].value

$pattern = "(?<=build=).*?(?=,)"
$build = [Regex]::Matches($sessiond, $pattern).groups[0].value

#========================== titlehub.xboxlive.com ==========================#
###\ Response\Body

#Replace empty line
#REGEX: ^[ \t]*$\r?\n

#Prefix every none empty line
#Search  = ^([A-Za-z0-9]+)$
#Replace = able:"\1"
# '^' points to the start of the line
# '$' points to the end of the line
# \1 or [{("'$&'")}] IS the source match within parentheses

$titles = Get-Content "$SourceFolder\$XblTitlehub"
$t = $titles | ConvertFrom-Json

#xuidtitles
$t.xuid
#titles
$t.titles
    #titleId
    $t.titles.titleId
    #pfn
    $t.titles.pfn
    #bingId
    $t.titles.bingId
    #serviceConfigId
    $t.titles.serviceConfigId
    #windowsPhoneProductId
    $t.titles.windowsPhoneProductId
    #name
    $t.titles.name
    #type
    $t.titles.type
    #devices
    $t.titles.devices
    #displayImage
    $t.titles.displayImage.
    #mediaItemType
    $t.titles.mediaItemType
    #modernTitleId
    $t.titles.modernTitleId
    #isBundle
    $t.titles.isBundle
    #achievement
    $t.titles.achievement
        #currentAchievements
        $t.titles.achievement.currentAchievements
        #totalAchievements
        $t.titles.achievement.totalAchievements
        #currentGamerscore
        $t.titles.achievement.currentGamerscore
        #totalGamerscore
        $t.titles.achievement.totalGamerscore
        #progressPercentage
        $t.titles.achievement.progressPercentage
        #sourceVersion
        $t.titles.achievement.sourceVersion
    #stats
    $t.titles.stats
    #images
    $t.titles.images
        #BoxArt
        $t.titles.images[0]
        #BrandedKeyArt
        $t.titles.images[1]
        #Poster
        $t.titles.images[2]
        #FeaturePromotionalSquareArt
        $t.titles.images[3]
        #ImageGallery
        $t.titles.images[4]
        #ImageGallery
        $t.titles.images[5]
        #ImageGallery
        $t.titles.images[6]
        #TitledHeroArt
        $t.titles.images[7]
        #SuperHeroArt
        $t.titles.images[8]
    #titleHistory
    $t.titles.titleHistory
        #lastTimePlayed
        $t.titles.titleHistory.lastTimePlayed
        #visible
        $t.titles.titleHistory.visible
        #canHide
        $t.titles.titleHistory.canHide
    #detail
    $t.titles.detail
    #friendsWhoPlayed
    $t.titles.friendsWhoPlayed
    #alternateTitleIds
    $t.titles.alternateTitleIds
    #contentBoards
    $t.titles.contentBoards
    #xboxLiveTier
    $t.titles.xboxLiveTier


#========================== accounts.xboxlive.com ==========================#
###\ Response\Body

$account = Get-Content "$SourceFolder\$XblAccounts"
$a = $account | ConvertFrom-Json

#familyId
$a.familyId
#familyUsers
$a.familyUsers
    #userId
    $a.familyUsers[0].userId
    #email
    $a.familyUsers[0].email
    #firstName
    $a.familyUsers[0].firstName
    #lastName
    $a.familyUsers[0].lastName
    #imageUrl
    $a.familyUsers[0].imageUrl
    #gamerTag
    $a.familyUsers[0].gamerTag
    #xuid
    $a.familyUsers[0].xuid
    #role
    $a.familyUsers[0].role
    #canViewRestrictedContent
    $a.familyUsers[0].canViewRestrictedContent
    #canViewTVAdultContent
    $a.familyUsers[0].canViewTVAdultContent
    #activityReporting
    $a.familyUsers[0].activityReporting
    #contentExceptions
    $a.familyUsers[0].contentExceptions
    #maturityLevel
    $a.familyUsers[0].maturityLevel
    #webFilteringLevel
    $a.familyUsers[0].webFilteringLevel
    #webFilteringExceptions
    $a.familyUsers[0].webFilteringExceptions
    #allowPurchaseAndDownloads
    $a.familyUsers[0].allowPurchaseAndDownloads


#========================== profile.xboxlive.com ==========================#
###\ Response\Body

$profile = Get-Content "$SourceFolder\$XblProfile"
$p = $profile | ConvertFrom-Json

#ID: Proporty Name, Value: Proporty value

#profileUsers[{ }]
$p.profileUsers
    #Id
    $p.profileUsers.id
    #hostId
    $p.profileUsers.hostId
    #isSponsoredUser
    $p.profileUsers.isSponsoredUser
    #settings[{ }]
    $p.profileUsers.settings
        #GameDisplayPicRaw
        $p.profileUsers.settings[0]
        #Gamerscore
        $p.profileUsers.settings[1]
        #Gamertag
        $p.profileUsers.settings[2]
        #AccountTier
        $p.profileUsers.settings[3]
        #XboxOneRep
        $p.profileUsers.settings[4]
        #PreferredColor
        $p.profileUsers.settings[5]
        #RealName
        $p.profileUsers.settings[6]
        #Bio
        $p.profileUsers.settings[7]
        #TenureLevel
        $p.profileUsers.settings[8]
        #Watermarks
        $p.profileUsers.settings[9]
        #Location
        $p.profileUsers.settings[10]
        #IsDeleted
        $p.profileUsers.settings[11]
        #ShowUserAsAvatar
        $p.profileUsers.settings[12]

Friday, July 13, 2018

PowerShell - Learning - Entry 1.4

Last one for the night, really. Added some clean up functions.

##

#Clean up on New Run or on application Exit
<#
    if($MainLoopEvent){
            Unregister-Event $MainLoopEvent -Force
            Stop-Job $MainLoopEvent
        }

        if($CrashEvent){
            Unregister-Event $CrashEvent -Force
            Stop-Job $CrashEvent
        }
#>

# Store all the start up variables so you can clean up when the script finishes.
New-Variable -force -name startupVariables -value ( Get-Variable | ForEach-Object { $_.Name } )

Function Clean-Memory
{
    Get-Variable |
    Where-Object { $startupVariables -notcontains $_.Name } |
    ForEach-Object
    { 
        try
        {
            Remove-Variable -Name "$($_.Name)" -Force -Scope "global" -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
        }
        catch { }
    }
}

### Clean up Memory Script
    function ReleaseObj ($ref) {

    [System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$ref) | out-null
    [System.GC]::Collect()
    [System.GC]::WaitForPendingFinalizers()

    }

### Clean up Memory + ShutDown Script
    function FinalizeEvent ($ref){

    Unregister-Event $ref
    ReleaseRef $ref
    Stop-Job $ref
    }

##


##

#Dummy Data
$SearchPath="$env:USERPROFILE\Desktop"
$SubDir=$false
$MainLoopAction ={
   Get-NewSource
   Update-DataObj
   Update-AppUi
   #Send-Notice
}
$CrashNotice ={
    Send-Notice
}

$CrashEvent = Set-WatchEvent (Make-Watcher <#CrashFodler#> "*.") -Action $CrashNotice

##
# "*.*" = All, "*." Directory
Function Make-Watcher($searchPath="$env:USERPROFILE\Desktop",$Filter="*.*", $subDir=$false) {
    $watcher = New-Object System.IO.FileSystemWatcher
    $watcher.Path = $searchPath
    $watcher.Filter = $Filter
    $watcher.IncludeSubdirectories = $subDir
    $watcher.EnableRaisingEvents = $true
    return $watcher
}

##
Function Set-WatchEvent($Object=$null,$Event="Created",$Action) {
    # Deleted, Renamed, Changed, Created; $changed = Register-ObjectEvent $watcher "Changed" -Action { write-host "Changed: $($eventArgs.FullPath)" }
    if($Object -ne $null){
        $created = Register-ObjectEvent $Object $Event -Action $Action # Watcher/Event & Action Code Source: https://superuser.com/questions/888442/powershell-folder-monitor-batch-execution
            #$action = {Invoke-Item "D:\BATCH FILES\XXXXX.bat" -filter = "XXXXX.pdf"}
        #while ($true) {sleep 5} #Only works if external job
        return $created
    }
}

#Test Functionality
$MainLoopEvent = Set-WatchEvent (Make-Watcher) -Action $MainLoopAction

##


##

# Get system info
# $sys | Get-Member -MemberType Property | ForEach{ "{0} = `t{1}" -f $_.name, $sys.($_.name) }

Function Send-Notice ($title="TestTracker Report",$msg="You have a waiting Action. Please Approve the Action.",$bttn='ok',$icon='Exclamation') {
    # Icon Info key Source: MSDN Icon Table: https://msdn.microsoft.com/en-us/library/system.windows.forms.messageboxicon(v=vs.110).aspx
    # TODO: Change frame, change icon to custom, change color; background, header, text
    #$wshell = New-Object -ComObject Wscript.Shell ##$wshell.Popup("Operation Completed",0,"Done",0x1)
    [System.Windows.Forms.MessageBox]::Show($msg,$title,$bttn,$icon) 
}

Function Get-NewSource {
    Write-Host (`
    "`n### `$newSource = Get-Content -Raw -Path `"`$env:USERPROFILE\Desktop\...`"",
    "`$newJson = ConvertFrom-Json `$newSource",
    "return `$newJson")
}

Function Get-Log {
    #Pull Profile
    Write-Host "`n### DataObj = NewSourceData"
}

Function Update-DataObj {
    Write-Host "`n### DataObj = NewSourceData"
}

Function Update-AppUi {
    Write-Host "`n### AppUI = UpdatedDataObj"
}

function Get-SystemInfo ($ComputerName=$env:ComputerName,$header = 'Hostname','OSName','OSVersion','OSManufacturer','OSConfig','Buildtype', 'RegisteredOwner','RegisteredOrganization','ProductID','InstallDate', 'StartTime','Manufacturer','Model','Type','Processor','BIOSVersion', 'WindowsFolder' ,'SystemFolder','StartDevice','Culture', 'UICulture', 'TimeZone','PhysicalMemory', 'AvailablePhysicalMemory' , 'MaxVirtualMemory', 'AvailableVirtualMemory','UsedVirtualMemory','PagingFile','Domain' ,'LogonServer','Hotfix','NetworkAdapter')
{
    #param($ComputerName = $env:ComputerName)
    $a = systeminfo.exe /FO CSV /S $ComputerName |
    Select-Object -Skip 1 |
    ConvertFrom-CSV -Header $header
    return $a
    #Flags:
        #/s Computer #Specifies the name or IP address of a remote computer (do not use backslashes). The default is the local computer.
        #/u Domain\User #Runs the command with the account permissions of the user specified by User or Domain\User. The default is the permissions of the current logged on user on the computer issuing the command.
        #/p Password #Specifies the password of the user account that is specified in the /u parameter.
        #/fo {Table|List|CSV} # Specifies the format to use for the output. Valid values are TABLE, LIST, and CSV. The default format for output is LIST.
        #/nh #Suppresses column headers in the output. Valid when the /fo parameter is set to TABLE or CSV.
        # Code Source https://gallery.technet.microsoft.com/scriptcenter/PowerShell-System-571521d1
}

function Get-Dxdiag {
    # Drop output in temp dir
    $logFile = $env:TEMP + "\dxDiagLog.xml"

    # Piping to Out-Null forces it to wait for dxdiag to complete before continuing.  Otherwise
    # it tries to load the file before it actuallygets written
    dxdiag.exe /whql:off /dontskip /x $logFile | Out-Null
    [xml]$dxDiagLog = Get-Content $logFile
    #$dxDiagLog.DxDiag.DirectSound.SoundDevices.SoundDevice | ft Description, DriverProvider
    # CODE SOURCE: https://stackoverflow.com/questions/37122010/can-i-access-dxdiag-from-powershell-console
    return $dxDiagLog
}

function Get-SystemData {
    $S = Get-SystemInfo
    $D = Get-Dxdiag
    $Sys = @{}

    #Gather relevant SystemInformation
    $Sys.add("Date",Get-Date)
    $Sys.add("Computer Name",$env:COMPUTERNAME)
    $Sys.add("OS",$S.OSVersion)
    $Sys.add("Language",$S.Culture)
    $Sys.add("System Manufacturer",$S.Manufacturer)# $S.OSManufacturer
    $Sys.add("System Model",$S.Model)
    $Sys.add("Bios",$S.BIOSVersion)
    $Sys.add("Processor",$D.DxDiag.SystemInformation.Processor)# $S.Processor
    $Sys.add("Memory",$D.DxDiag.SystemInformation.AvaliableOSMem)
    $Sys.add("Page File",$S.PagingFile)
    $Sys.add("DirectX Version",$D.DxDiag.SystemInformation.DirectXVersion)
    $Sys.add("Display Res",$D.DxDiag.DisplayDevices.DisplayDevice[1].CurrentMode)
    $Sys.add("MonitorName",$D.DxDiag.DisplayDevices.DisplayDevice[1].MonitorName)
    $Sys.add("MonitorId",$D.DxDiag.DisplayDevices.DisplayDevice[1].MonitorId)
    $Sys.add("NativeMode",$D.DxDiag.DisplayDevices.DisplayDevice[1].NativeMode)
    $Sys.add($S)
    $Sys.add($D)

    return $Sys
}

##


##

Function Set-AutoSession ($Check=$True) {
    if(Check){ Write-Host "`n### Auto is ON." }
    else{ Write-Host "`n### Auto is Off." }
}

Function StartSession {
    Write-Host "`n### Session Started!"
}

Function StopSession {
    Write-Host "`n### Session Stopped!"
}

Function Write-Token ($token=$null,$document=$null) {
    Write-Host "`n### `$token written to `$(`$document[0]) at line `$(`$document[1])."
}

Function Refresh-Token ($token=$null) {
    Write-Host "`n### `$token refreshed."
}


Function Copy-TokenToClipBoard ($token=$null) {
    <#
    Copy-TokenToClipBoard copies a passed token to the Windows Clipboard.
    Syntax; [$token = int,string]
    #>
    #Not Functional yet.
    #Set-Clipboard -Value $token
    Write-Host "`n### `$token copied to clipboard."
}

Function Set-DirectoryPath ($dir="") {
    Write-Host "`n### Path set to `$dir"
}

Function Set-Preferences ($AppPreferences) {
    Write-Host "`n### Preference saved!"
    $AppPreferences | Out-file $outFile
}

##

PowerShell - Learning - Entry 1.3

More coding, added getting system information from Dxdiag and system.exe. Along with some more place holder functions. Learning stuff yay! time for sleep before work! Booo sleep!

#Clean up on New Run or on application Exit
if($MainLoopEvent){
    Unregister-Event $MainLoopEvent -Force
    Stop-Job $MainLoopEvent
}

##

#Dummy Data
$SearchPath="$env:USERPROFILE\Desktop"
$SubDir=$false
$MainLoopAction ={
   Get-NewSource
   Update-DataObj
   Update-AppUi
   #Send-Notice
}

##
# "*.*" = All, "*." Directory
Function Make-Watcher($searchPath="$env:USERPROFILE\Desktop",$Filter="*.*", $subDir=$false) {
    $watcher = New-Object System.IO.FileSystemWatcher
    $watcher.Path = $searchPath
    $watcher.Filter = $Filter
    $watcher.IncludeSubdirectories = $subDir
    $watcher.EnableRaisingEvents = $true
    return $watcher
}

##
Function Set-WatchEvent($Object=$null,$Event="Created",$Action) {
    # Deleted, Renamed, Changed, Created; $changed = Register-ObjectEvent $watcher "Changed" -Action { write-host "Changed: $($eventArgs.FullPath)" }
    if($Object -ne $null){
        $created = Register-ObjectEvent $Object $Event -Action $Action # Watcher/Event & Action Code Source: https://superuser.com/questions/888442/powershell-folder-monitor-batch-execution
            #$action = {Invoke-Item "D:\BATCH FILES\XXXXX.bat" -filter = "XXXXX.pdf"}
        #while ($true) {sleep 5} #Only works if external job
        return $created
    }
}

#Test Functionality
$watcher = Make-Watcher
$MainLoopEvent = Set-WatchEvent $watcher -Action $MainLoopAction

##


##

# Get system info
# $sys | Get-Member -MemberType Property | ForEach{ "{0} = `t{1}" -f $_.name, $sys.($_.name) }

Function Send-Notice ($title="TestTracker Report",$msg="You have a waiting Action. Please Approve the Action.",$bttn='ok',$icon='Exclamation') {
    # Icon Info key Source: MSDN Icon Table: https://msdn.microsoft.com/en-us/library/system.windows.forms.messageboxicon(v=vs.110).aspx
    # TODO: Change frame, change icon to custom, change color; background, header, text
    #$wshell = New-Object -ComObject Wscript.Shell ##$wshell.Popup("Operation Completed",0,"Done",0x1)
    [System.Windows.Forms.MessageBox]::Show($msg,$title,$bttn,$icon) 
}

Function Get-NewSource {
    Write-Host (`
    "`n### `$newSource = Get-Content -Raw -Path `"`$env:USERPROFILE\Desktop\...`"",
    "`$newJson = ConvertFrom-Json `$newSource",
    "return `$newJson")
}

Function Update-DataObj {
    Write-Host "`n### DataObj = NewSourceData"
}

Function Update-AppUi {
    Write-Host "`n### AppUI = UpdatedDataObj"
}

function Get-SystemInfo ($ComputerName=$env:ComputerName,$header = 'Hostname','OSName','OSVersion','OSManufacturer','OSConfig','Buildtype', 'RegisteredOwner','RegisteredOrganization','ProductID','InstallDate', 'StartTime','Manufacturer','Model','Type','Processor','BIOSVersion', 'WindowsFolder' ,'SystemFolder','StartDevice','Culture', 'UICulture', 'TimeZone','PhysicalMemory', 'AvailablePhysicalMemory' , 'MaxVirtualMemory', 'AvailableVirtualMemory','UsedVirtualMemory','PagingFile','Domain' ,'LogonServer','Hotfix','NetworkAdapter')
{
    #param($ComputerName = $env:ComputerName)
    $a = systeminfo.exe /FO CSV /S $ComputerName |
    Select-Object -Skip 1 |
    ConvertFrom-CSV -Header $header
    return $a
    #Flags:
        #/s Computer #Specifies the name or IP address of a remote computer (do not use backslashes). The default is the local computer.
        #/u Domain\User #Runs the command with the account permissions of the user specified by User or Domain\User. The default is the permissions of the current logged on user on the computer issuing the command.
        #/p Password #Specifies the password of the user account that is specified in the /u parameter.
        #/fo {Table|List|CSV} # Specifies the format to use for the output. Valid values are TABLE, LIST, and CSV. The default format for output is LIST.
        #/nh #Suppresses column headers in the output. Valid when the /fo parameter is set to TABLE or CSV.
        # Code Source https://gallery.technet.microsoft.com/scriptcenter/PowerShell-System-571521d1
}

function Get-Dxdiag {
    # Drop output in temp dir
    $logFile = $env:TEMP + "\dxDiagLog.xml"

    # Piping to Out-Null forces it to wait for dxdiag to complete before continuing.  Otherwise
    # it tries to load the file before it actuallygets written
    dxdiag.exe /whql:off /dontskip /x $logFile | Out-Null
    [xml]$dxDiagLog = Get-Content $logFile
    #$dxDiagLog.DxDiag.DirectSound.SoundDevices.SoundDevice | ft Description, DriverProvider
    # CODE SOURCE: https://stackoverflow.com/questions/37122010/can-i-access-dxdiag-from-powershell-console
    return $dxDiagLog
}

function Get-SystemData {
    $S = Get-SystemInfo
    $D = Get-Dxdiag
    $Sys = @{}

    #Gather relevant SystemInformation
    $Sys.add("Date",Get-Date)
    $Sys.add("Computer Name",$env:COMPUTERNAME)
    $Sys.add("OS",$S.OSVersion)
    $Sys.add("Language",$S.Culture)
    $Sys.add("System Manufacturer",$S.Manufacturer)# $S.OSManufacturer
    $Sys.add("System Model",$S.Model)
    $Sys.add("Bios",$S.BIOSVersion)
    $Sys.add("Processor",$D.DxDiag.SystemInformation.Processor)# $S.Processor
    $Sys.add("Memory",$D.DxDiag.SystemInformation.AvaliableOSMem)
    $Sys.add("Page File",$S.PagingFile)
    $Sys.add("DirectX Version",$D.DxDiag.SystemInformation.DirectXVersion)
    $Sys.add("Display Res",$D.DxDiag.DisplayDevices.DisplayDevice[1].CurrentMode)
    $Sys.add("MonitorName",$D.DxDiag.DisplayDevices.DisplayDevice[1].MonitorName)
    $Sys.add("MonitorId",$D.DxDiag.DisplayDevices.DisplayDevice[1].MonitorId)
    $Sys.add("NativeMode",$D.DxDiag.DisplayDevices.DisplayDevice[1].NativeMode)
    return $Sys
}

##


##

Function Set-AutoSession ($Check=$True) {
    if(Check){ Write-Host "`n### Auto is ON." }
    else{ Write-Host "`n### Auto is Off." }
}

Function StartSession {
    Write-Host "`n### Session Started!"
}

Function StopSession {
    Write-Host "`n### Session Stopped!"
}

Function Write-Token ($token=$null,$document=$null) {
    Write-Host "`n### `$token written to `$(`$document[0]) at line `$(`$document[1])."
}

Function Refresh-Token ($token=$null) {
    Write-Host "`n### `$token refreshed."
}


Function Copy-TokenToClipBoard ($token=$null) {
    <#
    Copy-TokenToClipBoard copies a passed token to the Windows Clipboard.
    Syntax; [$token = int,string]
    #>
    #Not Functional yet.
    #Set-Clipboard -Value $token
    Write-Host "`n### `$token copied to clipboard."
}

Function Set-DirectoryPath ($dir="") {
    Write-Host "`n### Path set to `$dir"
}

Function Set-Preferences ($AppPreferences) {
    Write-Host "`n### Preference saved!"
    $AppPreferences | Out-file $outFile
}

##

PowerShell - Learning - Entry 1

Proof of connect for an application. This is the Main loop based on an event trigger. When new files are added to a watched directory the application will act on the file to extract useful information and propagate that to an application window for ease of viewing.

Writing the code in Sublime text 3, because it's just that great. and test running in PowerShell ISE.


#Clean up on New Run or on application Exit
if($MainLoopEvent){
    Unregister-Event $MainLoopEvent -Force
    Stop-Job $MainLoopEvent
}

##

#Dummy Data
$SearchPath="$env:USERPROFILE\Desktop"
$SubDir=$false
$MainLoopAction ={
   Get-NewSource
   Update-DataObj
   Update-AppUi
   Send-Notice
}

##
# "*.*" = All, "*." Directory
Function Make-Watcher($searchPath="$env:USERPROFILE\Desktop",$Filter="*.*", $subDir=$false) {
    $watcher = New-Object System.IO.FileSystemWatcher
    $watcher.Path = $searchPath
    $watcher.Filter = $Filter
    $watcher.IncludeSubdirectories = $subDir
    $watcher.EnableRaisingEvents = $true
    return $watcher
}

##
Function Set-WatchEvent($Object=$null,$Event="Created",$Action) {
    # Deleted, Renamed, Changed, Created; $changed = Register-ObjectEvent $watcher "Changed" -Action { write-host "Changed: $($eventArgs.FullPath)" }
    if($Object -ne $null){
        $created = Register-ObjectEvent $Object $Event -Action $Action #https://superuser.com/questions/888442/powershell-folder-monitor-batch-execution
            #$action = {Invoke-Item "D:\BATCH FILES\XXXXX.bat" -filter = "XXXXX.pdf"}
        #while ($true) {sleep 5} #Only works if external job
        return $created
    }
}

#Test Functionality
$watcher = Make-Watcher
$MainLoopEvent = Set-WatchEvent $watcher -Action $MainLoopAction

##

##

Function Send-Notice ($title="TestTracker Report",$msg="You have a waiting Action. Please Approve the Action.",$bttn='ok',$icon='Exclamation') {
    # MSDN Icon Table: https://msdn.microsoft.com/en-us/library/system.windows.forms.messageboxicon(v=vs.110).aspx
    # TODO: Change frame, change icon to custom, change color; background, header, text
    #$wshell = New-Object -ComObject Wscript.Shell ##$wshell.Popup("Operation Completed",0,"Done",0x1)
    [System.Windows.Forms.MessageBox]::Show($msg,$title,$bttn,$icon) 
}

Function Get-NewSource {
    Write-Host (`
    "`n### `$newSource = Get-Content -Raw -Path `"`$env:USERPROFILE\Desktop\...`"",
    "`$newJson = ConvertFrom-Json `$newSource",
    "return `$newJson")
}

Function Update-DataObj {
    Write-Host "`n### DataObj = NewSourceData"
}

Function Update-AppUi {
    Write-Host "`n### AppUI = UpdatedDataObj"
}

##