Public/SCJBServerTeamTools.ps1

function SCJBServerTeamTools {
    <#
    .LINK
        https://www.powershellgallery.com/packages/SCJBServerTeamTools
    .EXAMPLE
        SCJBServerTeamTools
        Open to the home window
    .EXAMPLE
        SCJBServerTeamTools -QuickLaunch ADLookups
        Open to the ADLookups window
    .EXAMPLE
        SCJBServerTeamTools -QuickLaunch RSOP
        Open to the RSOP window
    .EXAMPLE
        STT -QuickLaunch SCCMDeployments
        Open using the alias to the SCCM deployments window
    .EXAMPLE
        STT -ShowSettings
        Outputs the tools settings file in a PS object.
    #>


    # MAIN TODO
    # - function for creating windows (leave out variable creation) or a foreach of each .xml in the assets folder.
    # - help window
    # - users - member of sccm collection (probably doesn't matter, we have like 10 user collections)
    # - IntuneDeviceDetails needs to exit cleaner back to the home window when there is an error, such as failing to login to graph.
    # - _UpdateSCCMDevices use API instead
    # - SCCM Collection members
    # - datagrid header padding between columns
    # - hide first run output of LoganShell folder creation
    # - get smarter about looping through an object to create the pscustomobject dynamically for the datagrid
    # - getobjectsplat doesnt update when settings are changed. modify these things in the _loadsettings function?
    # - move 'constants' to this function.
    # - genericdatagrid renamed
    # - genericdatagrid CPU round to 0 or 2 decimal places
    # - figure out how to resort datagrids
    # - user tab - actions with a verify messagebox
    # - computer tab - install updates
    # - computer tab - schedule reboot
    # - user's group tab - if only 1 group, it gets mad. i think computer was the same way.
    # - verify that the settingssaved variable works correctly

    [CmdletBinding()]
    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Blackholes are fun.')]

    param (
        [Parameter(Mandatory = $false)]
        [ValidateSet('ADLookups', 'RSOP', 'SCCMDeployments', 'Query')]
        [string]
        $QuickLaunch,

        [Parameter(Mandatory = $false, HelpMessage='This will just output the contents of the settings file.')]
        [switch]
        $ShowSettings
    )

    # WPF framework
    Add-Type -AssemblyName PresentationFramework

    # Windows Form framework (message boxes)
    Add-Type -AssemblyName System.Windows.Forms
    # Add-Type -AssemblyName System.Drawing

    #region Pre-run checks and constants
    if ((Get-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools).State -eq 'NotPresent') {
        Write-Warning 'RSAT AD Tools must be installed prior to use.'
        break
    }

    try {
        $Script:PDC = Get-ADDomainController -Filter * | Where-Object OperationMasterRoles -Contains 'PDCEmulator'
    }
    catch {
        Write-Warning 'Unable to contact a domain controller.'
        break
    }

    $Script:Module = Get-Module SCJBServerTeamTools
    $Script:ModuleName = 'SCJBServerTeamTools'

    #endregion

    #region First Run
    Write-Verbose 'Checking for first run'
    if (!(Test-Path -Path $env:APPDATA\LoganShell\settings.json)) {
        # Settings file doesn't exist
        Write-Verbose 'First Run, creating directory and saving settings.'
        if (!(Test-Path -Path $env:APPDATA\LoganShell\)) {
            $Blackhole = New-Item -Path $env:APPDATA -Name 'LoganShell' -ItemType Directory
        }
        Write-Verbose 'Prompting for initial input'

        $userinput = Read-Host -Prompt 'Do you want to enable SCCM functionality? (Y/N)'
        switch ($userinput) {
            'Y' {
                $EnableSCCM = $true
                $SCCMServerInput = Read-Host -Prompt 'What is the hostname for the SCCM server?'
            }
            'N' {
                $EnableSCCM = $false
            }
            default {
                Write-Host 'Invalid option. Run again.'
                break
            }
        }

        $userinput = Read-Host -Prompt 'Do you want to enable Exchange on-premise functionality? (Y/N)'
        switch ($userinput) {
            'Y' {
                $EnableExchange = $true
            }
            'N' {
                $EnableExchange = $false
            }
            default {
                Write-Host 'Invalid option. Run again.'
                break
            }
        }

        Write-Verbose 'Setting temporary storage location'
        $ObjectFolder = 'C:\temp\Loganshell\'
        if (!(Test-Path $ObjectFolder)) {
            Write-Verbose 'Creating path.'
            New-Item -Path $ObjectFolder -ItemType Directory -Force -ErrorAction Stop
        }

        Write-Verbose 'Set PDCEmulator DC as default'
        $DefaultDC = $PDC.Name

        try {
            # Save default settings
            $InitialSplat = @{
                Path         = "$env:APPDATA\LoganShell\"
                SCCM         = $EnableSCCM
                SCCMServer   = $SCCMServerInput
                Exchange     = $EnableExchange
                DefaultDC    = $DefaultDC
                ObjectFolder = $ObjectFolder
            }
            _InitialSettings @InitialSplat -ErrorAction Stop
        }
        catch {
            throw $_
        }
        Write-Verbose 'Done setting up for first run.'
    }
    #endregion

    #region Loading Settings
    Write-Verbose 'Loading Settings'
    try {
        $Script:STTSettings = _LoadSettings -File $env:APPDATA\LoganShell\Settings.json -ErrorAction Stop
    }
    catch {
        throw $_
    }

    if ($ShowSettings) {
        Write-Output $STTSettings
        break
    }

    if ($STTSettings.DCSettings.DomainController) {
        $Script:GetObjectSplat = @{
            Server = $STTSettings.DCSettings.DomainController
        }
    }
    else {
        $Script:GetObjectSplat = @{
        }
    }

    if ($STTSettings.DCSettings.UseAlternateCredentials) {
        _LoadCredential
        $Script:SessionSplat = @{
            Credential = $StoredCredential
        }
    }
    else {
        $Script:SessionSplat = @{
        }
    }

    if ($STTSettings.Theme) {
        switch ($STTSettings.Theme) {
            'Light' {
                $ThemeFile = "$ModuleRoot\Assets\LightTheme.xaml"
            }
            'Dark' {
                $ThemeFile = "$ModuleRoot\Assets\DarkTheme.xaml"
            }
            'Violet' {
                $ThemeFile = "$ModuleRoot\Assets\VioletTheme.xaml"
            }
            Default {
                $ThemeFile = "$ModuleRoot\Assets\LightTheme.xaml"
            }
        }
    }
    else {
        # Old settings file
        $ThemeFile = "$ModuleRoot\Assets\LightTheme.xaml"
    }
    #endregion

    #region RSOP
    $xamlFile = "$ModuleRoot\Assets\RSOP.xaml"

    #create window
    $inputXML = Get-Content $xamlFile -Raw
    $inputXML = $inputXML -replace 'mc:Ignorable="d"', '' -replace 'x:N', 'N' -replace '^<Win.*', '<Window'
    [XML]$XAML = $inputXML
    $xaml.window.'Window.Resources'.ResourceDictionary.'ResourceDictionary.MergedDictionaries'.ResourceDictionary.Source = $ThemeFile

    #Read XAML
    $reader = (New-Object System.Xml.XmlNodeReader $xaml)
    try {
        $RSOP = [Windows.Markup.XamlReader]::Load( $reader )
    }
    catch {
        Write-Warning $_.Exception
        throw
    }

    $xaml.SelectNodes('//*[@Name]') | ForEach-Object {
        try {
            Set-Variable -Name "RSOP_$($_.Name)" -Value $RSOP.FindName($_.Name) -ErrorAction Stop
        }
        catch {
            throw
        }
    }
    #endregion

    #region ADLookups
    $xamlFile = "$ModuleRoot\Assets\ADLookups.xaml"

    #create window
    $inputXML = Get-Content $xamlFile -Raw
    $inputXML = $inputXML -replace 'mc:Ignorable="d"', '' -replace 'x:N', 'N' -replace '^<Win.*', '<Window'
    [XML]$XAML = $inputXML
    $xaml.window.'Window.Resources'.ResourceDictionary.'ResourceDictionary.MergedDictionaries'.ResourceDictionary.Source = $ThemeFile

    #Read XAML
    $reader = (New-Object System.Xml.XmlNodeReader $xaml)
    try {
        $ADLookups = [Windows.Markup.XamlReader]::Load( $reader )
    }
    catch {
        Write-Warning $_.Exception
        throw
    }

    $xaml.SelectNodes('//*[@Name]') | ForEach-Object {
        try {
            Set-Variable -Name "ADLookups_$($_.Name)" -Value $ADLookups.FindName($_.Name) -ErrorAction Stop
        }
        catch {
            throw
        }
    }
    #endregion

    #region SCCMDeployments
    $xamlFile = "$ModuleRoot\Assets\SCCMDeployments.xaml"

    #create window
    $inputXML = Get-Content $xamlFile -Raw
    $inputXML = $inputXML -replace 'mc:Ignorable="d"', '' -replace 'x:N', 'N' -replace '^<Win.*', '<Window'
    [XML]$XAML = $inputXML
    $xaml.window.'Window.Resources'.ResourceDictionary.'ResourceDictionary.MergedDictionaries'.ResourceDictionary.Source = $ThemeFile

    #Read XAML
    $reader = (New-Object System.Xml.XmlNodeReader $xaml)
    try {
        $SCCMDeployments = [Windows.Markup.XamlReader]::Load( $reader )
    }
    catch {
        Write-Warning $_.Exception
        throw
    }

    $xaml.SelectNodes('//*[@Name]') | ForEach-Object {
        try {
            Set-Variable -Name "SCCMDeployments_$($_.Name)" -Value $SCCMDeployments.FindName($_.Name) -ErrorAction Stop
        }
        catch {
            throw
        }
    }
    #endregion

    #region GenericDataGrid
    $xamlFile = "$ModuleRoot\Assets\GenericDataGrid.xaml"

    #create window
    $inputXML = Get-Content $xamlFile -Raw
    $inputXML = $inputXML -replace 'mc:Ignorable="d"', '' -replace 'x:N', 'N' -replace '^<Win.*', '<Window'
    [XML]$XAML = $inputXML
    $xaml.window.'Window.Resources'.ResourceDictionary.'ResourceDictionary.MergedDictionaries'.ResourceDictionary.Source = $ThemeFile

    #Read XAML
    $reader = (New-Object System.Xml.XmlNodeReader $xaml)
    try {
        $GenericDataGrid = [Windows.Markup.XamlReader]::Load( $reader )
    }
    catch {
        Write-Warning $_.Exception
        throw
    }

    $xaml.SelectNodes('//*[@Name]') | ForEach-Object {
        try {
            Set-Variable -Name "GenericDataGrid_$($_.Name)" -Value $GenericDataGrid.FindName($_.Name) -ErrorAction Stop
        }
        catch {
            throw
        }
    }
    #endregion

    #region Options
    $xamlFile = "$ModuleRoot\Assets\Options.xaml"

    #create window
    $inputXML = Get-Content $xamlFile -Raw
    $inputXML = $inputXML -replace 'mc:Ignorable="d"', '' -replace 'x:N', 'N' -replace '^<Win.*', '<Window'
    [XML]$XAML = $inputXML
    $xaml.window.'Window.Resources'.ResourceDictionary.'ResourceDictionary.MergedDictionaries'.ResourceDictionary.Source = $ThemeFile

    #Read XAML
    $reader = (New-Object System.Xml.XmlNodeReader $xaml)
    try {
        $Options = [Windows.Markup.XamlReader]::Load( $reader )
    }
    catch {
        Write-Warning $_.Exception
        throw
    }

    $xaml.SelectNodes('//*[@Name]') | ForEach-Object {
        try {
            Set-Variable -Name "Options_$($_.Name)" -Value $Options.FindName($_.Name) -ErrorAction Stop
        }
        catch {
            throw
        }
    }
    #endregion

    #region HomeWindow
    $xamlFile = "$ModuleRoot\Assets\HomeWindow.xaml"

    #create window
    $inputXML = Get-Content $xamlFile -Raw
    $inputXML = $inputXML -replace 'mc:Ignorable="d"', '' -replace 'x:N', 'N' -replace '^<Win.*', '<Window'
    [XML]$XAML = $inputXML
    $xaml.window.'Window.Resources'.ResourceDictionary.'ResourceDictionary.MergedDictionaries'.ResourceDictionary.Source = $ThemeFile

    #Read XAML
    $reader = (New-Object System.Xml.XmlNodeReader $xaml)
    try {
        $HomeWindow = [Windows.Markup.XamlReader]::Load( $reader )
    }
    catch {
        Write-Warning $_.Exception
        throw
    }

    $xaml.SelectNodes('//*[@Name]') | ForEach-Object {
        try {
            Set-Variable -Name "HomeWindow_$($_.Name)" -Value $HomeWindow.FindName($_.Name) -ErrorAction Stop
        }
        catch {
            throw
        }
    }
    #endregion

    _RSOPWindowUIEvents
    _ADLookupsUIEvents
    _SCCMDeploymentsUIEvents
    _GenericDataGridUIEvents
    _OptionsUIEvents
    _HomeWindowUIEvents

    # Get-Variable Options_* | Select-Object Name

    switch ($QuickLaunch) {
        'ADLookups' {
            Write-Output 'Loading ADLookups....'
            $null = $ADLookups.ShowDialog()
        }
        'RSOP' {
            Write-Output 'Loading RSOP....'
            $null = $RSOP.ShowDialog()
        }
        'SCCMDeployments' {
            Write-Output 'Loading SCCM Deployments....'
            $null = $SCCMDeployments.ShowDialog()
        }
        'Query' {
            Write-Output 'Loading Computer Query....'
            $null = $GenericDataGrid.ShowDialog()
        }
        Default {
            Write-Output 'Loading ServerTeamTools....'
            $null = $HomeWindow.ShowDialog()
        }
    }
}