ExoGraphGUI.psm1
$script:ModuleRoot = $PSScriptRoot $script:ModuleVersion = (Import-PowerShellDataFile -Path "$($script:ModuleRoot)\ExoGraphGUI.psd1").ModuleVersion # Detect whether at some level dotsourcing was enforced $script:doDotSource = Get-PSFConfigValue -FullName ExoGraphGUI.Import.DoDotSource -Fallback $false if ($ExoGraphGUI_dotsourcemodule) { $script:doDotSource = $true } <# Note on Resolve-Path: All paths are sent through Resolve-Path/Resolve-PSFPath in order to convert them to the correct path separator. This allows ignoring path separators throughout the import sequence, which could otherwise cause trouble depending on OS. Resolve-Path can only be used for paths that already exist, Resolve-PSFPath can accept that the last leaf my not exist. This is important when testing for paths. #> # Detect whether at some level loading individual module files, rather than the compiled module was enforced $importIndividualFiles = Get-PSFConfigValue -FullName ExoGraphGUI.Import.IndividualFiles -Fallback $false if ($ExoGraphGUI_importIndividualFiles) { $importIndividualFiles = $true } if (Test-Path (Resolve-PSFPath -Path "$($script:ModuleRoot)\..\.git" -SingleItem -NewChild)) { $importIndividualFiles = $true } if ("<was compiled>" -eq '<was not compiled>') { $importIndividualFiles = $true } function Import-ModuleFile { <# .SYNOPSIS Loads files into the module on module import. .DESCRIPTION This helper function is used during module initialization. It should always be dotsourced itself, in order to proper function. This provides a central location to react to files being imported, if later desired .PARAMETER Path The path to the file to load .EXAMPLE PS C:\> . Import-ModuleFile -File $function.FullName Imports the file stored in $function according to import policy #> [CmdletBinding()] Param ( [string] $Path ) $resolvedPath = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($Path).ProviderPath if ($doDotSource) { . $resolvedPath } else { $ExecutionContext.InvokeCommand.InvokeScript($false, ([scriptblock]::Create([io.file]::ReadAllText($resolvedPath))), $null, $null) } } #region Load individual files if ($importIndividualFiles) { # Execute Preimport actions foreach ($path in (& "$ModuleRoot\internal\scripts\preimport.ps1")) { . Import-ModuleFile -Path $path } # Import all internal functions foreach ($function in (Get-ChildItem "$ModuleRoot\internal\functions" -Filter "*.ps1" -Recurse -ErrorAction Ignore)) { . Import-ModuleFile -Path $function.FullName } # Import all public functions foreach ($function in (Get-ChildItem "$ModuleRoot\functions" -Filter "*.ps1" -Recurse -ErrorAction Ignore)) { . Import-ModuleFile -Path $function.FullName } # Execute Postimport actions foreach ($path in (& "$ModuleRoot\internal\scripts\postimport.ps1")) { . Import-ModuleFile -Path $path } # End it here, do not load compiled code below return } #endregion Load individual files #region Load compiled code <# This file loads the strings documents from the respective language folders. This allows localizing messages and errors. Load psd1 language files for each language you wish to support. Partial translations are acceptable - when missing a current language message, it will fallback to English or another available language. #> Import-PSFLocalizedString -Path "$($script:ModuleRoot)\en-us\*.psd1" -Module 'ExoGraphGUI' -Language 'en-US' Function Connect-ExoGraphGuiService { <# .SYNOPSIS Function to authenticate the user or App. .DESCRIPTION Function to authenticate the user or App. .PARAMETER ClientID String parameter with the ClientID (or AppId) of your AzureAD Registered App. .PARAMETER TenantID String parameter with the TenantID of your AzureAD tenant. .PARAMETER CertificateThumbprint String parameter with the certificate thumbprint which is configured in the AzureAD App. .EXAMPLE PS C:\> Connect-ExoGraphGuiService Authenticates the user or Azure App. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] [Cmdletbinding()] param( [String] $ClientID, [String] $TenantID, [String] $CertificateThumbprint ) DynamicParam { $modules = Get-Module Microsoft.Graph.Authentication $latest = $modules | Sort-Object version -Descending if ($latest[0].Version -ge [version]"2.0.0") { $Attribute = New-Object System.Management.Automation.ParameterAttribute $Attribute.Mandatory = $false $Attribute.HelpMessage = "String parameter with the Client Secret which is configured in the AzureAD App." #create an attributecollection object for the attribute we just created. $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] #add our custom attribute $attributeCollection.Add($Attribute) #add our paramater specifying the attribute collection $secretParam = New-Object System.Management.Automation.RuntimeDefinedParameter('ClientSecret', [String], $attributeCollection) #expose the name of our parameter $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $paramDictionary.Add('ClientSecret', $secretParam) return $paramDictionary } } Process { # Connect to Graph if there is no current context $conn = Get-MgContext $requiredScopes = "Mail.ReadWrite", "Mail.Send", "MailboxSettings.Read", "User.ReadWrite.All" if ( $conn ) { $compare = Compare-Object -ReferenceObject $conn.scopes -DifferenceObject $requiredScopes -IncludeEqual } if ( $null -eq $conn -or $compare.sideindicator -contains "=>" ) { Write-PSFMessage -Level Host -Message "There is currently no active connection to MgGraph or current connection is missing required scopes: $($requiredScopes -join ", ")" -FunctionName "ExoGraphGUI" if ( $clientID -ne '' -and $TenantID -ne '' -and ($CertificateThumbprint -ne '' -or $ClientSecret -ne '')) { # Connecting to graph using Azure App Application flow with passed parameters Write-PSFMessage -Level Host -Message "Connecting to graph with Azure AppId: $ClientID with passed parameters" -FunctionName "ExoGraphGUI" if ($PSBoundParameters.ContainsKey('CertificateThumbprint') ) { Connect-MgGraph -ClientId $ClientID -TenantId $TenantID -CertificateThumbprint $CertificateThumbprint } elseif ($PSBoundParameters.ContainsKey('ClientSecret') ) { $clientCredential = New-Object System.Net.NetworkCredential($ClientID, $ClientSecret) Connect-MgGraph -TenantId $TenantID -ClientSecretCredential $clientCredential } } elseif ( $null -ne (Get-PSFConfig -Module ExoGraphGUI -Name ClientID).value -and ` $null -ne (Get-PSFConfig -Module ExoGraphGUI -Name TenantID).value -and ` ($null -ne (Get-PSFConfig -Module ExoGraphGUI -Name ClientSecret).value -or $null -ne (Get-PSFConfig -Module ExoGraphGUI -Name CertificateThumbprint).value) ) { # Connecting to graph using Azure App Application flow saved values in the module Write-PSFMessage -Level Host -Message "Connecting to graph with Azure AppId: $((Get-PSFConfig -Module ExoGraphGUI -Name ClientID).value) with saved credentials in the module" -FunctionName "ExoGraphGUI" $cid = (Get-PSFConfig -Module ExoGraphGUI -Name ClientID).value $tid = (Get-PSFConfig -Module ExoGraphGUI -Name TenantID).value $cs = ConvertTo-SecureString -String (Get-PSFConfig -Module ExoGraphGUI -Name ClientSecret).value -AsPlainText -Force $ct = (Get-PSFConfig -Module ExoGraphGUI -Name CertificateThumbprint).value if ( $ct ) { Write-PSFMessage -Level Verbose -Message "Connecting to graph with Azure AppId: $cid with saved CertificateThumbprint" Connect-MgGraph -ClientId $cid -TenantId $tid -CertificateThumbprint $ct } else { Write-PSFMessage -Level Verbose -Message "Connecting to graph with Azure AppId: $cid with saved ClientSecret" $clientCredential = New-Object System.Net.NetworkCredential($cid, $cs) Connect-MgGraph -TenantId $tid -ClientSecretCredential $clientCredential } } else { # Connecting to graph with the user account Write-PSFMessage -Level Host -Message "Connecting to graph with the user account" -FunctionName "ExoGraphGUI" Connect-MgGraph -Scopes $requiredScopes } $conn = Get-MgContext } if ( $null -eq $conn.Account ) { Write-PSFMessage -Level Host -Message "Currently connected with App Account: $($conn.AppName)" -FunctionName "ExoGraphGUI" } else { Write-PSFMessage -Level Host -Message "Currently connected with User Account: $($conn.Account)" -FunctionName "ExoGraphGUI" } return $conn } } Function Get-FolderList { <# .SYNOPSIS Method to list folders in the user mailbox. .DESCRIPTION Method to list folders in the user mailbox, showing Folder name, FolderId, Number of items, and number of subfolders. Module required: Microsoft.Graph.Mail Scope needed: Delegated: Mail.ReadBasic Application: Mail.ReadBasic.All .PARAMETER Account User's UPN to get mail folders from. .EXAMPLE PS C:\> Get-FolderList lists folders in the user mailbox. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param( $Account ) $statusBarLabel.Text = "Running..." Function Find-Subfolders { Param ( $Account, $array, $ParentFolderId, $ParentDisplayname ) foreach ($folder in (Get-MgUserMailFolderChildFolder -UserId $Account -MailFolderId $ParentFolderId -All -Property *)) { $folderpath = $ParentDisplayname + $folder.DisplayName $line = $folder | Select-Object @{N="FolderPath";E={$folderpath}},ChildFolderCount,TotalItemCount,UnreadItemCount,Id $null = $array.add($line) if ( $folder.ChildFolderCount -gt 0 ) { Find-Subfolders -Account $Account -ParentFolderId $folder.id -Array $array -ParentDisplayname "$folderpath\" } } } #listing all available folders in the mailbox $array = New-Object System.Collections.ArrayList if ($radiobutton1.Checked) { $parentFolders = (Get-MgUserMailFolder -UserId $Account -MailFolderId "msgfolderRoot").Id } elseif ($radiobutton2.Checked) { $deletions = Get-MgUserMailFolder -UserId $Account -MailFolderId "recoverableitemsdeletions" $parentFolders = $deletions.ParentFolderId } Find-Subfolders -Account $Account -ParentFolderId $parentFolders -Array $array -ParentDisplayname "\" $dgResults.datasource = $array $dgResults.AutoResizeColumns() $dgResults.Visible = $True $txtBoxResults.Visible = $False $PremiseForm.refresh() $statusBarLabel.Text = "Ready. Folders found: $($array.Count)" if ($radiobutton1.Checked) { Write-PSFMessage -Level Output -Message "Succesfully listed folders in the primary Mailbox" -FunctionName "Method 1" -Target $Account } elseif ($radiobutton2.Checked) { Write-PSFMessage -Level Output -Message "Succesfully listed folders in Recoverable Items" -FunctionName "Method 2" -Target $Account } } Function Get-ItemsInFolder { <# .SYNOPSIS Method to list items in a specific folders in the user mailbox. .DESCRIPTION Method to list items in a specific folders in the user mailbox. Module required: Microsoft.Graph.Mail Scope needed: Delegated: Mail.ReadBasic Application: Mail.ReadBasic.All .PARAMETER Account User's UPN to get mail messages from. .PARAMETER folderID FolderID value to get mail messages from. .PARAMETER StartDate StartDate to search for items. .PARAMETER EndDate EndDate to search for items. .PARAMETER MsgSubject Optional parameter to search based on a subject text. .EXAMPLE PS C:\> Get-ItemsInFolder Method to list items in a specific folders in the user mailbox. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "")] [CmdletBinding()] Param( [String] $Account, [String] $folderID, [string] $StartDate, [string] $EndDate, [String] $MsgSubject ) $statusBarLabel.Text = "Running..." if ( $folderID -ne "" ) { # Creating Filter variables $filter = $null if ($MsgSubject -ne "") { $filter = "Subject eq '$MsgSubject'" } $sourceFolderName = (get-mgusermailFolder -UserId $Account -MailFolderId $FolderID).Displayname $array = New-Object System.Collections.ArrayList $msgs = Get-MgUserMailFolderMessage -UserId $Account -MailFolderId $folderID -Filter $filter -All | Where-Object {$_.ReceivedDateTime -ge $StartDate -and $_.ReceivedDateTime -lt $EndDate} | Select-Object subject, @{N = "Sender"; E = { $_.Sender.EmailAddress.Address } }, ReceivedDateTime, isRead $null = $msgs | ForEach-Object { $array.Add($_) } $dgResults.datasource = $array $dgResults.AutoResizeColumns() $dgResults.Visible = $True $txtBoxResults.Visible = $False $PremiseForm.refresh() $statusBarLabel.text = "Ready. Items found: $($array.Count)" Write-PSFMessage -Level Output -Message "Succesfully listed items in folder '$sourceFolderName'." -FunctionName "Method 3" -Target $Account } else { [Microsoft.VisualBasic.Interaction]::MsgBox("FolderID textbox is empty. Check and try again", [Microsoft.VisualBasic.MsgBoxStyle]::Okonly, "Information Message") $statusBarLabel.text = "Method 6 finished with warnings/errors" } } Function Get-UserDelegates { <# .SYNOPSIS Get user's Delegates information .DESCRIPTION Get user's Delegates information Module required: Microsoft.Graph.Authentication Scope needed: Delegated: MailboxSettings.Read Application: MailboxSettings.Read .PARAMETER Account User's UPN to get delegate settings from. .EXAMPLE PS C:\> Get-UserDelegates Get user's Delegates information #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param( $Account ) $statusBarLabel.Text = "Running..." $txtBoxResults.Text = "This function is still under construction." #TODO $response = Invoke-MgGraphRequest -Method get -Uri https://graph.microsoft.com/v1.0/users/$Account/mailboxSettings $response["delegateMeetingMessageDeliveryOptions"] $dgResults.Visible = $False $txtBoxResults.Visible = $True $PremiseForm.refresh() $statusBarLabel.text = "Ready." Write-PSFMessage -Level Host -Message "Task finished succesfully" -FunctionName "Method 10" -Target $Account } Function Get-UserInboxRule { <# .SYNOPSIS Method to get user's Inbox Rules. Module required: Microsoft.Graph.Mail Scope needed: Delegated: MailboxSettings.Read Application: MailboxSettings.Read .DESCRIPTION Method to get user's Inbox Rules. .PARAMETER Account User's UPN to get mail folders from. .EXAMPLE PS C:\> Get-UserInboxRule Method to get user's Inbox Rules. #> [CmdletBinding()] param( [String] $Account ) $statusBarLabel.Text = "Running..." $array = New-Object System.Collections.ArrayList $rules = Get-MgUserMailFolderMessageRule -UserId $Account -MailFolderId "Inbox" foreach ( $rule in $rules ) { $output = $rule | Select-Object DisplayName, HasError, IsEnabled, IsReadOnly, Sequence $array.Add($output) Write-PSFMessage -Level Verbose -Message $output -FunctionName "Method6" -Target $Account } $dgResults.datasource = $array $dgResults.AutoResizeColumns() $dgResults.Visible = $True $txtBoxResults.Visible = $False $PremiseForm.refresh() $statusBarLabel.text = "Ready..." Write-PSFMessage -Level Host -Message "Succesfully retrieved inbox rules." -FunctionName "Method 6" -Target $Account } Function Get-UserOOFSettings { <# .SYNOPSIS Method to get user's OOF Settings. Module required: Microsoft.Graph.Authentication Scope needed: Delegated: MailboxSettings.Read Application: MailboxSettings.Read .DESCRIPTION Method to get user's OOF Settings. .PARAMETER Account User's UPN to get OOF settings from. .EXAMPLE PS C:\> Get-UserOOFSettings Method to get user's OOF Settings. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")] [CmdletBinding()] param( [String] $Account ) $statusBarLabel.Text = "Running..." $response = Invoke-MgGraphRequest -Method Get -Uri "https://graph.microsoft.com/v1.0/users/$Account/mailboxSettings/automaticRepliesSetting" $array = New-Object System.Collections.ArrayList $output = $response | Select-Object ` @{ Name = "Status" ; Expression = { $response["Status"] } }, ` @{ Name = "ExternalAudience" ; Expression = { $response["externalAudience"] } }, ` @{ Name = "StartTime" ; Expression = { $response["scheduledStartDateTime"].DateTime.ToString("yyyy/MM/dd HH:mm:ss") } }, ` @{ Name = "EndTime" ; Expression = { $response["scheduledEndDateTime"].DateTime.ToString("yyyy/MM/dd HH:mm:ss") } }, ` @{ Name = "InternalReplyMessage" ; Expression = { $response["InternalReplyMessage"] } }, ` @{ Name = "ExternalReplyMessage" ; Expression = { $response["ExternalReplyMessage"] } } $array.Add($output) Write-PSFMessage -Level Verbose -Message $output -FunctionName "Method 7" -Target $Account $dgResults.datasource = $array $dgResults.AutoResizeColumns() $dgResults.Visible = $True $txtBoxResults.Visible = $False $PremiseForm.refresh() $statusBarLabel.text = "Ready..." Write-PSFMessage -Level Host -Message "Succesfully retrieved OOF settings." -FunctionName "Method 7" -Target $Account } function Get-UserProfilePicture { <# .SYNOPSIS Method to get user's profile picture from graph. .DESCRIPTION Long description Module required: Microsoft.Graph.Mail Scope needed: Delegated: User.ReadWrite.All Application: User.ReadWrite.All .PARAMETER Account User's UPN to switch to. .EXAMPLE PS C:\> Get-UserProfilePicture -Account "user@domain.com" Gets user's profile picture from user "user@domain.com". #> [CmdletBinding()] param ( [String] $Account ) $statusBarLabel.Text = "Running..." try { $filepath = "$env:temp\profilephoto$(Get-Random).jpg" Write-PSFMessage -Level Verbose -Message "Setting profile picture downloaded file path to: $filepath" -FunctionName "Method 13" -Target $Account Invoke-MgGraphRequest -Method get -Uri "https://graph.microsoft.com/v1.0/users/$Account/photo/`$value" -OutputFilePath $filepath -ErrorAction Stop $Image = [System.Drawing.Image]::Fromfile($filepath) $pictureBox.Image = $Image.GetThumbnailImage(140, 140, $null, 0) $PremiseForm.refresh() $statusBarLabel.text = "Ready. Profile picture retrieved." Write-PSFMessage -Level Host -Message "Succesfully retrieved profile picture." -FunctionName "Method 13" -Target $Account } catch { Write-PSFMessage -Level Error -Message "The user doesn't seem to have a photo." -Target $Account $statusBarLabel.text = "Ready. The user doesn't seem to have a photo." } } Function Move-ItemsBetweenFolder { <# .SYNOPSIS Method to move items between folders. .DESCRIPTION Method to move items between folders by using FolderID values. Module required: Microsoft.Graph.Users.Actions Scope needed: Delegated: Mail.ReadWrite Application: Mail.ReadWrite .PARAMETER Account User's UPN to get move messages from. .PARAMETER FolderID FolderID value to get mail messages from. .PARAMETER TargetFolderID FolderID value to move mail messages to. .PARAMETER StartDate StartDate to search for items. .PARAMETER EndDate EndDate to search for items. .PARAMETER MsgSubject Optional parameter to search based on a subject text. .EXAMPLE PS C:\> Move-ItemsBetweenFolder Moves items from source folder to target folder based on dates and/or subject filters. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "")] [CmdletBinding()] Param( [String] $Account, [String] $FolderID, [String] $TargetFolderID, [string] $StartDate, [string] $EndDate, [String] $MsgSubject ) $statusBarLabel.Text = "Running..." if ( $FolderID -ne "" -and $TargetFolderID -ne "") { $sourceFolderName = (get-mgusermailFolder -UserId $Account -MailFolderId $FolderID).Displayname $targetFolderName = (get-mgusermailFolder -UserId $Account -MailFolderId $TargetFolderID).Displayname # Creating Filter variables $filter = $null if ($MsgSubject -ne "") { $filter = "Subject eq '$MsgSubject'" } $array = New-Object System.Collections.ArrayList $params = @{ DestinationId = $TargetFolderID } $msgs = Get-MgUserMailFolderMessage -UserId $Account -MailFolderId $folderID -Filter $filter -All | Where-Object { $_.ReceivedDateTime -ge $StartDate -and $_.ReceivedDateTime -lt $EndDate } | Select-Object id, subject, @{N = "Sender"; E = { $_.Sender.EmailAddress.Address } }, ReceivedDateTime, isRead [int]$i = 0 foreach ( $msg in $msgs ) { $i++ $output = $msg | Select-Object @{Name = "Action"; Expression = { "Moving Item" } }, ReceivedDateTime, Subject Move-MgUserMessage -UserId $Account -MessageId $msg.Id -BodyParameter $params $array.Add($output) Write-PSFMessage -Level Verbose -Message $output -FunctionName "Method 8" -Target $Account } $dgResults.datasource = $array $dgResults.AutoResizeColumns() $dgResults.Visible = $True $txtBoxResults.Visible = $False $PremiseForm.refresh() $statusBarLabel.text = "Ready. Moved Items: $i" Write-PSFMessage -Level Host -Message "Succesfully moved items from '$sourceFolderName' to '$targetFolderName'." -FunctionName "Method 8" -Target $Account } else { [Microsoft.VisualBasic.Interaction]::MsgBox("FolderID textbox or TargetFolderID is empty. Check and try again", [Microsoft.VisualBasic.MsgBoxStyle]::Okonly, "Information Message") $statusBarLabel.text = "Process finished with warnings/errors" } } Function New-CustomFolder { <# .SYNOPSIS Method to create a custom folder in mailbox's Root. .DESCRIPTION Method to create a custom folder in mailbox's Root. Module required: Microsoft.Graph.Mail Scope needed: Delegated: Mail.ReadWrite Application: Mail.ReadWrite .PARAMETER Account User's UPN to create mail folder to. .PARAMETER DisplayName DisplayName of the folder to be created. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .EXAMPLE PS C:\> New-CustomFolder Method to create a custom folder in mailbox's Root. #> [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')] param( [String] $Account, [String] $DisplayName ) if ( $DisplayName -ne "" ) { $statusBarLabel.text = "Running..." $params = @{ DisplayName = $DisplayName IsHidden = $false } New-MgUserMailFolder -UserId $Account -BodyParameter $params Write-PSFMessage -Level Host -Message "Succesfully created folder: $DisplayName" -FunctionName "Method 4" -Target $Account $statusBarLabel.text = "Ready..." $PremiseForm.Refresh() } else { [Microsoft.VisualBasic.Interaction]::MsgBox("FolderID textbox is empty. Check and try again",[Microsoft.VisualBasic.MsgBoxStyle]::Okonly,"Information Message") $statusBarLabel.text = "Method 7 finished with warnings/errors" } } Function New-EmailInInbox { <# .SYNOPSIS Function to inject an email messages through MS Graph. .DESCRIPTION Function to inject an email messages through MS Graph. Module required: Microsoft.Graph.Mail Scope needed: Delegated: Mail.ReadWrite Application: Mail.ReadWrite .PARAMETER Account User's UPN to inject the email message from. .PARAMETER ToRecipients List of recipients in the "To" list. If ommitted, it will be used the same as the logged on user. .PARAMETER NumberOfMessages Number of messages to be injected into the Inbox folder. By default is 1. .PARAMETER Subject Use this parameter to set the subject's text. By default will have: "Test message sent via Graph". .PARAMETER Body Use this parameter to set the body's text. By default will have: "Test message sent via Graph using Powershell". .PARAMETER UseAttachment Use this switch parameter to add an attachment to sample messages. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .EXAMPLE PS C:\> New-EmailInInbox -ToRecipients "john@contoso.com" Then will inject the email message to "john@contoso.com" from the user previously authenticated into the user's Inbox. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidGlobalVars", "")] [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')] Param ( [String] $Account, [String[]] $ToRecipients, [int] $NumberOfMessages = 1, [String] $Subject, [String] $Body, [Switch] $UseAttachment ) $statusBarLabel.Text = "Running..." if ( $ToRecipients -eq "" ) { $ToRecipients = $Account } if ( $subject -eq "" ) { $Subject = "Test message injected via Graph" } if ( $Body -eq "" ) { $Body = "Test message injected via Graph using ExoGraphGUI tool" } # Base mail body Hashtable $global:MailBody = @{ Importance = "Low" Sender = @{ EmailAddress = @{ Address = $Account } } Subject = $Subject Body = @{ Content = $Body ContentType = "HTML" } parentFolderId = (Get-MgUserMailFolder -UserId $Account -MailFolderId "inbox").Id } $attachParams = $null if ( $UseAttachment ) { # create sample attachment file if ( -not(test-path "$env:Temp\SampleFileName.txt") ) { $progresBar = New-BTProgressBar -Indeterminate -Status "working" New-burntToastNotification -ProgressBar $progresBar -UniqueIdentifier "bar001" -Text "Creating sample file" [int]$i = 0 1..5000 | ForEach-Object { $i++ Write-Progress -activity "Creating sample file. Please wait..." -status "Percent scanned: " -PercentComplete ($i * 100 / 5000) -ErrorAction SilentlyContinue "test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. test file for ExoGraphGUI tool. " | Add-Content -Path "$env:Temp\SampleFileName.txt" -Force } } $fileContentInBytes = [System.Text.Encoding]::UTF8.GetBytes((Get-Content -path "$env:Temp\SampleFileName.txt")) $attachParams = @{ "@odata.type" = "#microsoft.graph.fileAttachment" Name = "SampleFileName.txt" ContentBytes = [System.Convert]::ToBase64String($fileContentInBytes) } } # looping through each recipient in the list, and adding it in the hash table $recipientsList = New-Object System.Collections.ArrayList foreach ( $recipient in ($ToRecipients.split(",").Trim()) ) { $recipientsList.add( @{ EmailAddress = @{ Address = $recipient } } ) } $global:MailBody.Add("ToRecipients", $recipientsList) # Making Graph call to inject email message try { [int]$i = 0 $progresBar = New-BTProgressBar -Indeterminate -Status "working" New-burntToastNotification -ProgressBar $progresBar -UniqueIdentifier "bar001" -Text "Creating sample messages" 1..$NumberOfMessages | ForEach-Object { $i++ Write-Progress -activity "Creating sample message. $i / $NumberOfMessages" -status "Percent scanned: " -PercentComplete ($i * 100 / $NumberOfMessages) -ErrorAction SilentlyContinue $msg = New-MgUserMessage -UserId $Account -BodyParameter $MailBody if ( $UseAttachment ) { New-MgUserMessageAttachment -UserId $Account -MessageId $msg.Id -BodyParameter $attachParams } Move-MgUserMessage -UserId $Account -MessageId $msg.id -DestinationId "inbox" Write-PSFMessage -Level Verbose -Message "Succesfully injected email '$Subject'." -FunctionName "Method 12" -Target $Account } $statusBarLabel.text = "Ready. Mail injected." Write-PSFMessage -Level Host -Message "Succesfully injected sample message '$subject' into Inbox." -FunctionName "Method 12" -Target $Account } catch { $statusBarLabel.text = "Something failed to inject the email message using graph. Ready." Write-PSFMessage -Level Error -Message "Something failed to inject the email message using graph. Error message: $_" -FunctionName "Method 12" -Target $Account } } Function Remove-ItemsInFolder { <# .SYNOPSIS Method to Delete a subset of items in a folder. .DESCRIPTION Method to Delete a subset of items in a folder using Date Filters and/or subject. Module required: Microsoft.Graph.Mail Scope needed: Delegated: Mail.ReadWrite Application: Mail.ReadWrite .PARAMETER Account User's UPN to get delete messages from. .PARAMETER FolderID FolderID value to get mail messages from. .PARAMETER StartDate StartDate to search for items. .PARAMETER EndDate EndDate to search for items. .PARAMETER MsgSubject Optional parameter to search based on a subject text. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .EXAMPLE PS C:\> Remove-ItemsInFolder Method to Delete a subset of items in a folder. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "")] [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')] param( [String] $Account, [String] $FolderID, [string] $StartDate, [string] $EndDate, [String] $MsgSubject ) $statusBarLabel.Text = "Running..." if ( $FolderID -ne "" ) { $sourceFolderName = (get-mgusermailFolder -UserId $Account -MailFolderId $FolderID).Displayname # Creating Filter variables $filter = $null if ($MsgSubject -ne "") { $filter = "Subject eq '$MsgSubject'" } $array = New-Object System.Collections.ArrayList [int]$i = 0 $msgs = Get-MgUserMailFolderMessage -UserId $Account -MailFolderId $folderID -Filter $filter -All | Where-Object { $_.ReceivedDateTime -ge $StartDate -and $_.ReceivedDateTime -lt $EndDate } | Select-Object id, subject, ReceivedDateTime foreach ( $msg in $msgs ) { $i++ Remove-MgUserMessage -UserId $Account -MessageId $msg.Id $output = $msg | Select-Object @{Name="Action";Expression={"Deleting Item"}}, ReceivedDateTime, Subject Write-PSFMessage -Level Verbose -Message $output -FunctionName "Method9" -Target $Account $array.Add($output) } $dgResults.datasource = $array $dgResults.AutoResizeColumns() $dgResults.Visible = $True $txtBoxResults.Visible = $False $PremiseForm.refresh() $statusBarLabel.text = "Ready. Deleted items: $i" Write-PSFMessage -Level Host -Message "Succesfully deleted messages from folder: $sourceFolderName." -FunctionName "Method 9" -Target $Account } else { [Microsoft.VisualBasic.Interaction]::MsgBox("FolderID textbox is empty. Check and try again",[Microsoft.VisualBasic.MsgBoxStyle]::Okonly,"Information Message") $statusBarLabel.text = "Process finished with warnings/errors" } } Function Remove-SpecificFolder { <# .SYNOPSIS Method to delete a specific folder in the user mailbox. .DESCRIPTION Method to delete a specific folder in the user mailbox with 3 different deletion methods. Module required: Microsoft.Graph.Mail Scope needed: Delegated: Mail.ReadWrite Application: Mail.ReadWrite .PARAMETER Account User's UPN to delete mail folder from. .PARAMETER FolderId FolderId of the folder to be deleted. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .EXAMPLE PS C:\> Remove-SpecificFolder Method to delete a specific folder in the user mailbox. #> [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')] param( [String] $Account, [String] $FolderId ) $statusBarLabel.Text = "Running..." if ( $FolderId -ne "" ) { Remove-MgUserMailFolder -UserId $Account -MailFolderId $FolderId Write-PSFMessage -Level Host -Message "Succesfully removed folder $folderID." -FunctionName "Method 5" -Target $Account $statusBarLabel.text = "Ready..." $PremiseForm.Refresh() } else { [Microsoft.VisualBasic.Interaction]::MsgBox("FolderID textbox is empty. Check and try again",[Microsoft.VisualBasic.MsgBoxStyle]::Okonly,"Information Message") $statusBarLabel.text = "Process finished with warnings/errors" } } function Save-ProfilePicture { <# .SYNOPSIS Saves new profile picture into the user's pofile. .DESCRIPTION Saves new profile picture into the user's pofile. Module required: Microsoft.Graph.Authentication Scope needed: Delegated: User.ReadWrite.All Application: User.ReadWrite.All .PARAMETER Account User's UPN to save the new picture to. .PARAMETER NewProfilePicture File path to the new profile picture. .EXAMPLE PS C:\> Save-ProfilePicture -Account $Account -NewProfilePicture "C:\temp\photo.jpg" Saves photo "C:\temp\photo.jpg" to the user $Account. #> [CmdletBinding()] param ( [String] $Account, [String] $NewProfilePicture ) try { $statusBarLabel.Text = "Running..." Write-PSFMessage -Level Verbose -Message "uploading profile picture from: $NewProfilePicture" -FunctionName "Method 14" -Target $Account if ( $PSVersionTable.PSVersion.Major -lt 7) { $requestBody = Get-Content $NewProfilePicture -Raw -Encoding Byte } else { $requestBody = Get-Content $NewProfilePicture -AsByteStream -Raw } Invoke-MgGraphRequest -Method PUT -Uri "https://graph.microsoft.com/v1.0/users/$Account/photo/`$value" -Body $requestBody -ContentType "image/jpeg" -ErrorAction Stop $statusBarLabel.text = "Ready. Profile picture saved." Write-PSFMessage -Level Host -Message "Succesfully saved profile picture." -FunctionName "Method 14" -Target $Account } catch { Write-PSFMessage -Level Error -Message "Something failed to upload new profile picture. Error message. $_" -Target $Account $statusBarLabel.text = "Ready. Something failed to upload new profile picture." } } function Select-ProfilePicture { <# .SYNOPSIS Opens dialog box to pick new picture. .DESCRIPTION Opens dialog box to pick new picture. .EXAMPLE PS C:\> Select-ProfilePicture Opens dialog box to pick new picture. #> [OutputType([String])] [CmdletBinding()] param ( # Parameters ) $statusBarLabel.Text = "Running..." $OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog $OpenFileDialog.InitialDirectory = [Environment]::GetFolderPath("MyPictures") $OpenFileDialog.Filter = "Image Files(*.BMP;*.JPG;*.GIF;*.PNG)|*.BMP;*.JPG;*.GIF;*.PNG|All files (*.*)|*.*" $null = $OpenFileDialog.ShowDialog() Write-PSFMessage -Level Verbose -Message "Selected profile picture file path: $($OpenFileDialog.FileName)" -FunctionName "Method 14" -Target $Account $Image = [System.Drawing.Image]::Fromfile($OpenFileDialog.FileName) $pictureBox.Image = $Image.GetThumbnailImage(140, 140, $null, 0) $PremiseForm.refresh() $statusBarLabel.text = "Ready. Profile picture selected." Write-PSFMessage -Level Host -Message "Succesfully selected new profile picture." -FunctionName "Method 14" -Target $Account return $OpenFileDialog.FileName } Function Send-GraphEmailMessage { <# .SYNOPSIS Function to send email messages through MS Graph. .DESCRIPTION Function to send email messages through MS Graph. Module required: Microsoft.Graph.Users.Actions Scope needed: Delegated: Mail.Send Application: Mail.Send .PARAMETER Account User's UPN to send the email message from. .PARAMETER ToRecipients List of recipients in the "To" list. This is a Mandatory parameter. If no value is passed, it will take the same user account being used. .PARAMETER CCRecipients List of recipients in the "CC" list. This is an optional parameter. .PARAMETER BccRecipients List of recipients in the "Bcc" list. This is an optional parameter. .PARAMETER Subject Use this parameter to set the subject's text. By default will have: "Test message sent via Graph". .PARAMETER Body Use this parameter to set the body's text. By default will have: "Test message sent via Graph using Powershell". .EXAMPLE PS C:\> Send-GraphEmailMessage -ToRecipients "john@contoso.com" Then will send the email message to "john@contoso.com" from the user previously authenticated. .EXAMPLE PS C:\> Send-GraphEmailMessage -ToRecipients "julia@contoso.com","carlos@contoso.com" -BccRecipients "mark@contoso.com" -Subject "Lets meet!" Then will send the email message to "julia@contoso.com" and "carlos@contoso.com" and bcc to "mark@contoso.com", from the user previously authenticated. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidGlobalVars", "")] [Cmdletbinding()] Param ( [String] $Account, [parameter(Mandatory = $true)] [String[]] $ToRecipients, [String[]] $CCRecipients, [String[]] $BccRecipients, [String] $Subject, [String] $Body ) $statusBarLabel.Text = "Running..." if ( $ToRecipients -eq "") { $ToRecipients = $Account } if ( $subject -eq "" ) { $Subject = "Test message sent via Graph" } if ( $Body -eq "" ) { $Body = "Test message sent via Graph using ExoGraphGUI tool" } # Base mail body Hashtable $global:MailBody = @{ Message = @{ Subject = $Subject Body = @{ Content = $Body ContentType = "HTML" } } savetoSentItems = "true" } # looping through each recipient in the list, and adding it in the hash table $recipientsList = New-Object System.Collections.ArrayList foreach ( $recipient in ($ToRecipients.split(",").Trim()) ) { $recipientsList.add( @{ EmailAddress = @{ Address = $recipient } } ) } $global:MailBody.Message.Add("ToRecipients", $recipientsList) # looping through each recipient in the CC list, and adding it in the hash table if ( $CCRecipients -ne "" ) { $ccRecipientsList = New-Object System.Collections.ArrayList foreach ( $cc in $CCRecipients.split(",").Trim()) { $null = $ccRecipientsList.add( @{ EmailAddress = @{ Address = $cc } } ) } $MailBody.Message.Add("CcRecipients", $ccRecipientsList) } # looping through each recipient in the Bcc list, and adding it in the hash table if ( $BccRecipients -ne "" ) { $BccRecipientsList = New-Object System.Collections.ArrayList foreach ( $bcc in $BccRecipients.split(",").Trim()) { $null = $BccRecipientsList.add( @{ EmailAddress = @{ Address = $bcc } } ) } $MailBody.Message.Add("BccRecipients", $BccRecipientsList) } # Making Graph call to send email message try { Send-MgUserMail -UserId $Account -BodyParameter $MailBody -ErrorAction Stop $statusBarLabel.text = "Ready. Mail sent." Write-PSFMessage -Level Verbose -Message "Succesfully sent email '$Subject' to $ToRecipients, $CCRecipients, $BccRecipients." -FunctionName "Method 11" -Target $Account Write-PSFMessage -Level Host -Message "Succesfully sent email '$Subject'." -FunctionName "Method 11" -Target $Account } catch { $statusBarLabel.text = "Something failed to send the email message using graph. Ready." Write-PSFMessage -Level Error -Message "Something failed to send the email message using graph. Error message: $_" -FunctionName "Method 11" -Target $Account } } Function Start-ModuleUpdate { <# .SYNOPSIS Function to start checking for updates on this module. .DESCRIPTION Function to start checking for updates on this module. .PARAMETER ModuleRoot Modules root path. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .EXAMPLE PS C:\> Start-ModuleUpdate -ModuleRoot "C:\Temp" Runs the function to start checking for update for current module in "C:\Temp" #> [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')] Param ( [String]$ModuleRoot ) $ScriptBlock = { Param ( [String]$ModuleRoot ) $moduleManifest = (Import-PowerShellDataFile -Path "$((Get-ChildItem -Path $ModuleRoot -Filter *.psd1).Fullname)") $moduleFileName = $moduleManifest.RootModule $moduleName = $ModuleFileName.Substring(0, $ModuleFileName.IndexOf(".")) $script:ModuleVersion = $moduleManifest.ModuleVersion -as [version] $GalleryModule = Find-Module -Name $ModuleName -Repository PSGallery if ( $script:ModuleVersion -lt $GalleryModule.version ) { # if newer version is found in PSGallery, we will show a toast notification $bt = New-BTButton -Content "Get Update" -Arguments "$($moduleManifest.PrivateData.PSData.ProjectUri)#installation" New-BurntToastNotification -Text "$ModuleName Update found", "There is a new version $($GalleryModule.version) of this module available." -Button $bt } } # Create Runspace, set maximum threads $pool = [RunspaceFactory]::CreateRunspacePool(1, 1) $pool.ApartmentState = "MTA" $pool.Open() $runspace = [PowerShell]::Create() $runspace.Runspace.Name = "$ModuleName.Update" $null = $runspace.AddScript( $ScriptBlock ) $null = $runspace.AddArgument( $ModuleRoot ) $runspace.RunspacePool = $pool [PSCustomObject]@{ Pipe = $runspace Status = $runspace.BeginInvoke() Pool = $pool } } Function Stop-ModuleUpdate { <# .SYNOPSIS Function to stop checking for updates on this module and clear runspaces. .DESCRIPTION Function to stop checking for updates on this module and clear runspaces. .PARAMETER RunspaceData Runspace data retrieved from intial Start-ModuleUpdate function. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .EXAMPLE PS C:\> Stop-ModuleUpdate -RunspaceData $data Runs the function to stop checking for update on this module and clear runspaces. #> [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')] Param( $RunspaceData ) # Receive Results and cleanup $null = $RunspaceData.Pipe.EndInvoke($RunspaceData.Status) $RunspaceData.Pipe.Dispose() # Cleanup Runspace Pool $RunspaceData.pool.Close() $RunspaceData.pool.Dispose() } Function Switch-AnotherMailbox { <# .SYNOPSIS Method to switch to another mailbox. .DESCRIPTION Method to switch to another mailbox. .PARAMETER Account User's UPN to switch to. .EXAMPLE PS C:\> Switch-AnotherMailbox Method to switch to another mailbox. #> [OutputType([String])] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidGlobalVars", "")] [CmdletBinding()] param( [String] $Account ) $statusBarLabel.Text = "Running..." if ( $Account -ne "" ) { $labImpersonation.Location = New-Object System.Drawing.Point(440,200) $labImpersonation.Size = New-Object System.Drawing.Size(300,20) $labImpersonation.Name = "labImpersonation" $labImpersonation.ForeColor = "Blue" $PremiseForm.Controls.Add($labImpersonation) $labImpersonation.Text = $Account $PremiseForm.Text = "Managing user: " + $Account + ". Choose your Option" Write-PSFMessage -Level Host -Message "Succesfully switched to user account: $Account" -FunctionName "Method 15" -Target $Account $statusBarLabel.text = "Ready..." $PremiseForm.Refresh() return $Account } else { [Microsoft.VisualBasic.Interaction]::MsgBox("Email Address textbox is empty. Check and try again",[Microsoft.VisualBasic.MsgBoxStyle]::Okonly,"Information Message") $statusBarLabel.text = "Process finished with warnings/errors" } } function Export-ExoGraphGuiLog { <# .SYNOPSIS This function will export current PSFramework logs. .DESCRIPTION This function will export current PSFramework logs based on the amount of days old define in the 'DaysOld' parameter. It will allow to export to CSV file and/or display in powershell GridView. Output will have the following header: "ComputerName","Username","Timestamp","Level","Message","Type","FunctionName","ModuleName","File","Line","Tags","TargetObject","Runspace","Callstack" .PARAMETER FilePath Defines the path file to export the CSV file. Default value is the user's Desktop with a file name like "yyyy-MM-dd HH_mm_ss" - EWSGui logs.csv" .PARAMETER OutputType Defines the output types available. Can be a single output or combined. Current available options are CSV, GridView. .PARAMETER DaysOld Defines how old we will go to fetch the logs. Valid range is between 1 through 7 days old. Default Value is 1 .EXAMPLE PS C:\> Export-ExoGraphGuiLog -OutputType CSV In this example, the script will fetch all logs within the last 24 hrs (by default), and export to CSV to default location at the Desktop. .EXAMPLE PS C:\> Export-ExoGraphGuiLog -OutputType GridView -DaysOld 3 In this example, the script will fetch all logs within the last 3 days, and displays them in powershell's GridView. .EXAMPLE PS C:\> Export-ExoGraphGuiLog -OutputType CSV,GridView -DaysOld 5 In this example, the script will fetch all logs within the last 5 days, export to CSV to default location at the Desktop and also displays in powershell's GridView. .EXAMPLE PS C:\> Export-ExoGraphGuiLog -OutputType CSV,GridView -DaysOld 7 -FilePath "C:\Temp\newLog.csv" In this example, the script will fetch all logs within the last 7 days, export to CSV to path "C:\Temp\newLog.csv" and also displays them in powershell's GridView. #> [CmdletBinding()] Param ( [ValidateScript({ if ($_ -notmatch "(\.csv)") { throw "The file specified in the path argument must be of type CSV" } return $true })] [String]$FilePath = "$([Environment]::GetFolderPath("Desktop"))\$(get-date -Format "yyyy-MM-dd HH_mm_ss") - ExoGraphGui logs.csv", [ValidateSet('CSV', 'GridView')] [string[]]$OutputType = "GridView", [ValidateRange(1, 7)] [int]$DaysOld = 1 ) # creating folder path if it doesn't exists $folderPath = ([System.IO.FileInfo]$FilePath).DirectoryName if ( -not (Test-Path $folderPath) ) { Write-PSFMessage -Level Warning -Message "Folder '$folderPath' does not exists. Creating folder." $null = New-Item -Path $folderPath -ItemType Directory -Force } Import-module PSFramework $loggingpath = (Get-PSFConfig PSFramework.Logging.FileSystem.LogPath).Value $logFiles = Get-ChildItem -Path $loggingpath | Where-Object LastwriteTime -gt (Get-Date).adddays(-1 * $DaysOld) $csv = Import-Csv -Path $logFiles.FullName $output = $csv | Where-Object ModuleName -eq "ExoGraphGui" | Select-Object @{N = "Date"; E = { ($_.timestamp -split " ")[0] } }, @{N = "Time"; E = { Get-Date ($_.timestamp.Substring($_.timestamp.IndexOf(" ")).trim()) -Format HH:mm:ss } }, ` "ComputerName", "Username", "Level", "FunctionName", "Message", "Type", "ModuleName", "File", "Line", "Tags", "TargetObject", "Runspace", "Callstack" | Sort-Object Date -Descending Switch ( $OutputType) { CSV { $output | Sort-Object Date,Time -Descending | export-csv -Path $FilePath -NoTypeInformation } GridView { $output | Sort-Object Date,Time -Descending | Out-GridView } } } function Import-ExoGraphGUIAADAppDataa { <# .SYNOPSIS Function to Import ClientID, TenantID and ClientSecret to the ExoGraphGUI powershell module. .DESCRIPTION Function to Import ClientID, TenantID and ClientSecret to the ExoGraphGUI powershell module. .PARAMETER ClientID String parameter with the ClientID (or AppId) of your AzureAD Registered App. .PARAMETER TenantID String parameter with the TenantID your AzureAD tenant. .PARAMETER CertificateThumbprint String parameter with the certificate's thumbprint associated to your AzureAD App registration. .PARAMETER ClientSecret String parameter with the Client Secret which is configured in the AzureAD App. .EXAMPLE PS C:\> Import-ExoGraphGUIAADAppDataa -ClientID "your app client ID" -TenantID "Your tenant ID" -ClientSecret "your Secret passcode" The script will Import these values in the ExoGraphGUI module to be used automatically. #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [String] $ClientID, [Parameter(Mandatory = $true)] [String] $TenantID, [Parameter(Mandatory = $false, ParameterSetName = "Certificate")] $CertificateThumbprint, [Parameter(Mandatory = $false, ParameterSetName = "ClientSecret")] [String] $ClientSecret ) begin { if ( $ClientID -eq '' -or $TenantID -eq '' -or $CertificateThumbprint -eq '' -or $ClientSecret -eq '') { throw "Either ClientID, TenantID or CertificateThumbprint/ClientSecret are null or empty." } } process { Write-PSFMessage -Level Important -Message "Importing ClientID string to ExoGraphGUI Module." Set-PSFConfig -Module ExoGraphGUI -Name "ClientID" -Value $ClientID -Description "AppID of your Azure Registered App" -AllowDelete -PassThru | Register-PSFConfig Write-PSFMessage -Level Important -Message "Importing TenantID string to ExoGraphGUI Module." Set-PSFConfig -Module ExoGraphGUI -Name "TenantID" -Value $TenantID -Description "TenantID where your Azure App is registered." -AllowDelete -PassThru | Register-PSFConfig if ( $PSBoundParameters.ContainsKey("CertificateThumbprint") ) { Write-PSFMessage -Level Important -Message "Importing CertificateThumbprint string to ExoGraphGUI Module." Set-PSFConfig -Module ExoGraphGUI -Name "CertificateThumbprint" -Value $CertificateThumbprint -Description "CertificateThumbprint for your Azure App" -AllowDelete -PassThru | Register-PSFConfig } elseif ($PSBoundParameters.ContainsKey("ClientSecret") ) { Write-PSFMessage -Level Important -Message "Importing ClientSecret string to ExoGraphGUI Module." Set-PSFConfig -Module ExoGraphGUI -Name "ClientSecret" -Value $ClientSecret -Description "ClientSecret passcode for your Azure App" -AllowDelete -PassThru | Register-PSFConfig } } } Function Register-ExoGraphGUIApp { <# .SYNOPSIS Function to create the Azure App Registration for ExoGraphGUI. .DESCRIPTION Function to create the Azure App Registration for ExoGraphGUI. It will require an additional PS module "Microsoft.Graph.Applications", if not already installed it will download it. It will use these app scopes for the app "Mail.ReadWrite", "Mail.Send", "MailboxSettings.Read". You can use the "UseClientSecret" switch parameter to configure a new ClientSecret for the app. If this parameter is ommitted, we will use a Certificate. You can pass a certificate path if you have an existing certificate, or leave the parameter blank and a new self-signed certificate will be created. .PARAMETER AppName The friendly name of the app registration. By default will be "ExoGraphGUI Registered App". .PARAMETER TenantId Optional parameter to set the TenantID GUID. .PARAMETER CertPath The file path to your .CER public key file. If this parameter is ommitted, and the "UseClientSecret" is not used, we will be creating a new self-signed certificate (with a validity period of 1 year) for the app. .PARAMETER UseClientSecret Use this optional parameter, to configure a ClientSecret (with a validity period of 1 year) instead of a certificate. .PARAMETER ImportAppDataToModule Use this optional parameter to import your app's ClientId, TenantId and ClientSecret into the ExoGraphGUI module. In this way, the next time you run the app it will use the Application flow to authenticate with these values. .EXAMPLE PS C:\> Register-ExoGraphGUIApp.ps1 -AppName "Graph DemoApp" The Function will create a new AzureAD App Registration. The name of the app will be "ExoGraphGui Registered App". It will add the following API Permissions: **"Mail.ReadWrite", "MailboxSettings.Read"**. It will use a self-signed Certificate. Once the app is created, the Function will expose the link to grant "Admin consent" for the permissions requested. .NOTES General notes #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")] [Cmdletbinding()] param( [Parameter(Mandatory = $false)] [String] $AppName = "ExoGraphGUI Registered App", [Parameter(Mandatory = $false)] [String] $TenantId, [Parameter(Mandatory = $false)] [String] $CertPath, [Parameter(Mandatory = $false)] [Switch] $UseClientSecret, [Parameter(Mandatory = $false)] [Switch] $ImportAppDataToModule ) # Required modules Write-PSFMessage -Level Verbose -Message "Looking for required 'Microsoft.Graph.Applications' powershell module" if ( -not(Get-module "Microsoft.Graph.Applications" -ListAvailable) ) { Install-Module "Microsoft.Graph.Applications" -Scope CurrentUser -Force } Import-Module "Microsoft.Graph.Applications" # Graph permissions variables #$graphResourceId = "00000002-0000-0ff1-ce00-000000000000" $graphResourceId = "00000003-0000-0000-c000-000000000000" $scopesArray = New-Object System.Collections.ArrayList @("Mail.ReadWrite", "Mail.Send", "MailboxSettings.Read") | ForEach-Object { New-Variable perm -Value @{ Id = (Find-MgGraphPermission -SearchString $_ -PermissionType Application -ExactMatch).id Type = "Role" } $null = $scopesArray.add($perm) remove-variable perm } # Get context for access to tenant ID $context = Get-MgContext if ( $null -eq $context -or $context.Scopes -notcontains "Application.ReadWrite.All") { # Requires an admin Write-PSFMessage -Level Important -Message "Connecting to MgGraph" if ($TenantId) { Connect-MgGraph -Scopes "Application.ReadWrite.All User.Read" -TenantId $TenantId } else { Connect-MgGraph -Scopes "Application.ReadWrite.All User.Read" } } # Load cert if ( $CertPath ) { $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertPath) Write-PSFMessage -Level Host -Message "Certificate loaded from Path '$CertPath'." } elseif ( -not($UseClientSecret) ) { # Create certificate $docsPath = [Environment]::GetFolderPath("myDocuments") $mycert = New-SelfSignedCertificate -DnsName $context.Account.Split("@")[1] -CertStoreLocation "cert:\CurrentUser\My" -NotAfter (Get-Date).AddYears(1) -KeySpec KeyExchange # Export certificate to .pfx file $mycert | Export-PfxCertificate -FilePath "$docsPath\exographgui_cert.pfx" -Password (ConvertTo-SecureString -String "LS1setup!" -AsPlainText -Force ) -Force # Export certificate to .cer file $mycert | Export-Certificate -FilePath "$docsPath\exographgui_mycert.cer" -Force $cerPath = Get-ChildItem -Path "$docsPath\exographgui_mycert.cer" $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($cerPath.FullName) Write-PSFMessage -Level Host -Message "Certificate created in Path '$($cerPath.FullName)'." } # Create app registration if ( -not($UseClientSecret) ) { $appRegistration = New-MgApplication -DisplayName $AppName -SignInAudience "AzureADMyOrg" ` -Web @{ RedirectUris = "http://localhost"; } ` -RequiredResourceAccess @{ ResourceAppId = $graphResourceId; ResourceAccess = $scopesArray.ToArray() } ` -AdditionalProperties @{} -KeyCredentials @(@{ Type = "AsymmetricX509Cert"; Usage = "Verify"; Key = $cert.RawData }) Write-PSFMessage -Level Important -Message "App registration created with app ID $($appRegistration.AppId)" Write-PSFMessage -Level Important -Message "You can now connect running: Start-ExoGraphGUI -ClientID $($appRegistration.AppId) -TenantID $($context.TenantId) -CertificateThumbprint $($cert.Thumbprint)" } else { $appRegistration = New-MgApplication -DisplayName $AppName -SignInAudience "AzureADMyOrg" ` -Web @{ RedirectUris = "http://localhost"; } ` -RequiredResourceAccess @{ ResourceAppId = $graphResourceId; ResourceAccess = $scopesArray.ToArray() } ` -AdditionalProperties @{} $appObjId = Get-MgApplication -Filter "AppId eq '$($appRegistration.Appid)'" $passwordCred = @{ displayName = 'Secret created in PowerShell' endDateTime = (Get-Date).Addyears(1) } $secret = Add-MgApplicationPassword -applicationId $appObjId.Id -PasswordCredential $passwordCred Write-PSFMessage -Level Important -Message "App registration created with app ID $($appRegistration.AppId)" Write-PSFMessage -Level Important -Message "Please take note of your client secret as it will not be shown anymore" Write-PSFMessage -Level Important -Message "You can now connect running: Start-ExoGraphGUI -ClientID $($appRegistration.AppId) -TenantID $($context.TenantId) -ClientSecret $($secret.SecretText)" } # Create corresponding service principal New-MgServicePrincipal -AppId $appRegistration.AppId -AdditionalProperties @{} | Out-Null Write-PSFMessage -Level Verbose -Message "Service principal created" # Generate admin consent URL $adminConsentUrl = "https://login.microsoftonline.com/" + $context.TenantId + "/adminconsent?client_id=" + $appRegistration.AppId Write-PSFMessage -Level Important -Message "Please go to the following URL in your browser to provide admin consent:" Write-PSFMessage -Level Important -Message "$adminConsentUrl" if ( $ImportAppDataToModule ) { if ( -not($UseClientSecret) ) { Import-ExoGraphGUIAADAppData -ClientID $appRegistration.AppId -TenantID $context.TenantId -CertificateThumbprint $($cert.Thumbprint) } else { Import-ExoGraphGUIAADAppData -ClientID $appRegistration.AppId -TenantID $context.TenantId -ClientSecret $secret.SecretText } } } function Remove-ExoGraphGUIAADAppData { <# .SYNOPSIS Function to remove ClientID, TenantID and ClientSecret to the ExoGraphGUI powershell module. .DESCRIPTION Function to remove ClientID, TenantID and ClientSecret to the ExoGraphGUI powershell module. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .EXAMPLE PS C:\> Remove-ExoGraphGUIAADAppData The script will Remove these values in the ExoGraphGUI module to be used automatically. #> [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')] param ( # Parameters ) begin { } process { Write-PSFMessage -Level Important -Message "Removing ClientID, TenantID and ClientSecret strings from ExoGraphGUI Module." Unregister-PSFConfig -Module ExoGraphGUI remove-PSFConfig -Module ExoGraphGUI -Name clientID -Confirm:$false remove-PSFConfig -Module ExoGraphGUI -Name tenantID -Confirm:$false remove-PSFConfig -Module ExoGraphGUI -Name ClientSecret -Confirm:$false } end { } } Function Start-ExoGraphGUI { <# .SYNOPSIS Allows to perform 11 different operations using Graph with Exchange Online. .DESCRIPTION Allows to perform 11 different operations using Graph with Exchange Online: 1) List Folders in Root 2) List folders in Recoverable Items Root folder 3) List Items in a desired Folder 4) Create a custom Folder in Root 5) Delete a Folder 6) Get user's Inbox Rules 7) Get user's OOF Settings 8) Move items between folders 9) Delete a subset of items in a folder 10) Get user's Delegate information 11) Send mail message 12) Switch to another Mailbox .PARAMETER ClientID This is an optional parameter. String parameter with the ClientID (or AppId) of your AzureAD Registered App. .PARAMETER TenantID This is an optional parameter. String parameter with the TenantID your AzureAD tenant. .PARAMETER CertificateThumbprint This is an optional parameter. String parameter with the certificate thumbprint which is configured in the AzureAD App. .PARAMETER ClientSecret This is an optional parameter. String parameter with the Client Secret which is configured in the AzureAD App. .PARAMETER Confirm If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. .EXAMPLE PS C:\ Start-ExoGraphGUI Runs the GUI tool to use with Exchange Online. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidGlobalVars", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSReviewUnusedParameter", "")] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "")] [CmdletBinding(SupportsShouldProcess = $True, ConfirmImpact = 'Low')] param( [String] $ClientID, [String] $TenantID, #[Parameter(Mandatory = $false, ParameterSetName="Certificate")] [String] $CertificateThumbprint, #[Parameter(Mandatory = $false, ParameterSetName="ClientSecret")] [String] $ClientSecret ) $script:nl = "`r`n" #$ProgressPreference = "SilentlyContinue" $runspaceData = Start-ModuleUpdate -ModuleRoot $script:ModuleRoot function GenerateForm { #region Import the Assemblies Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing Add-Type -AssemblyName Microsoft.VisualBasic [System.Windows.Forms.Application]::EnableVisualStyles() #endregion #region Generated Form Objects $PremiseForm = New-Object System.Windows.Forms.Form $radiobutton1 = New-Object System.Windows.Forms.RadioButton $radiobutton2 = New-Object System.Windows.Forms.RadioButton $radiobutton3 = New-Object System.Windows.Forms.RadioButton $radiobutton4 = New-Object System.Windows.Forms.RadioButton $radiobutton5 = New-Object System.Windows.Forms.RadioButton $radiobutton6 = New-Object System.Windows.Forms.RadioButton $radiobutton7 = New-Object System.Windows.Forms.RadioButton $radiobutton8 = New-Object System.Windows.Forms.RadioButton $radiobutton9 = New-Object System.Windows.Forms.RadioButton $radiobutton10 = New-Object System.Windows.Forms.RadioButton $radiobutton11 = New-Object System.Windows.Forms.RadioButton $radiobutton12 = New-Object System.Windows.Forms.RadioButton $radiobutton13 = New-Object System.Windows.Forms.RadioButton $radiobutton14 = New-Object System.Windows.Forms.RadioButton $radiobutton15 = New-Object System.Windows.Forms.RadioButton $radiobutton16 = New-Object System.Windows.Forms.RadioButton $labImpersonation = New-Object System.Windows.Forms.Label $buttonGo = New-Object System.Windows.Forms.Button $buttonExit = New-Object System.Windows.Forms.Button $labFromDate = New-Object System.Windows.Forms.Label $global:FromDatePicker = New-Object System.Windows.Forms.DateTimePicker $labToDate = New-Object System.Windows.Forms.Label $global:ToDatePicker = New-Object System.Windows.Forms.DateTimePicker $labSubject = New-Object System.Windows.Forms.Label $global:txtBoxSubject = New-Object System.Windows.Forms.TextBox $labFolderID = New-Object System.Windows.Forms.Label $global:txtBoxFolderID = New-Object System.Windows.Forms.TextBox $labTargetFolderID = New-Object System.Windows.Forms.Label $global:txtBoxTargetFolderID = New-Object System.Windows.Forms.TextBox $labToRecipients = New-Object System.Windows.Forms.Label $global:txtBoxToRecipients = New-Object System.Windows.Forms.TextBox $labCCRecipients = New-Object System.Windows.Forms.Label $global:txtBoxCCRecipients = New-Object System.Windows.Forms.TextBox $labBCCRecipients = New-Object System.Windows.Forms.Label $global:txtBoxBCCRecipients = New-Object System.Windows.Forms.TextBox $labMailSubject = New-Object System.Windows.Forms.Label $global:txtboxMailSubject = New-Object System.Windows.Forms.TextBox $labMailBody = New-Object System.Windows.Forms.Label $global:txtBoxMailBody = New-Object System.Windows.Forms.TextBox $labNumOfMsgs = New-Object System.Windows.Forms.Label $global:NumericNumOfMsgs = New-Object System.Windows.Forms.NumericUpDown $UseAttachment = New-Object System.Windows.Forms.Label $global:checkboxUseAttachment = New-Object System.Windows.Forms.Checkbox $labAttachmentsWarning = New-Object System.Windows.Forms.Label $pictureBox = new-object Windows.Forms.PictureBox $buttonSelectPicture = New-Object System.Windows.Forms.Button $buttonSavePicture = New-Object System.Windows.Forms.Button $dgResults = New-Object System.Windows.Forms.DataGridView $txtBoxResults = New-Object System.Windows.Forms.Label $InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState #endregion Generated Form Objects # Connecting to EWS and creating service object $service = Connect-ExoGraphGuiService -ClientID $ClientID -TenantID $TenantID -CertificateThumbprint $CertificateThumbprint $Global:Account = $service.Account if (-not($service.Account)) { $Global:Account = [Microsoft.VisualBasic.Interaction]::InputBox("Enter user's UPN to work with", "ExoGraphGUI", "") } $ExpandFilters = { # Removing all controls, in order to reload the screen appropiately for each selection $PremiseForm.Controls.RemoveByKey("FromDate") $PremiseForm.Controls.RemoveByKey("FromDatePicker") $PremiseForm.Controls.RemoveByKey("ToDate") $PremiseForm.Controls.RemoveByKey("ToDatePicker") $PremiseForm.Controls.RemoveByKey("labSubject") $PremiseForm.Controls.RemoveByKey("txtBoxSubject") $PremiseForm.Controls.RemoveByKey("labFolderID") $PremiseForm.Controls.RemoveByKey("txtBoxFolderID") $PremiseForm.Controls.RemoveByKey("txtBoxTargetFolderID") $PremiseForm.Controls.RemoveByKey("labTargetFolderID") $PremiseForm.Controls.RemoveByKey("labToRecipients") $PremiseForm.Controls.RemoveByKey("txtBoxToRecipients") $PremiseForm.Controls.RemoveByKey("labCCRecipients") $PremiseForm.Controls.RemoveByKey("txtBoxCCRecipients") $PremiseForm.Controls.RemoveByKey("labBCCRecipients") $PremiseForm.Controls.RemoveByKey("txtBoxBCCRecipients") $PremiseForm.Controls.RemoveByKey("labMailSubject") $PremiseForm.Controls.RemoveByKey("txtBoxMailSubject") $PremiseForm.Controls.RemoveByKey("labMailbody") $PremiseForm.Controls.RemoveByKey("txtboxMailBody") $PremiseForm.Controls.RemoveByKey("labNumOfMsgs") $PremiseForm.Controls.RemoveByKey("NumericNumOfMsgs") $PremiseForm.Controls.RemoveByKey("UseAttachment") $PremiseForm.Controls.RemoveByKey("checkboxUseAttachment") $PremiseForm.Controls.RemoveByKey("PictureBox") $PremiseForm.Controls.RemoveByKey("buttonSelectPicture") $PremiseForm.Controls.RemoveByKey("buttonSavePicture") #Label FromDate $labFromDate.Location = New-Object System.Drawing.Point(5, 285) $labFromDate.Size = New-Object System.Drawing.Size(80, 35) $labFromDate.Name = "FromDate" $labFromDate.Text = "From or greater than" # FromDate Date Picker $FromDatePicker.DataBindings.DefaultDataSourceUpdateMode = 0 $FromDatePicker.Location = New-Object System.Drawing.Point(100, 285) $FromDatePicker.Name = "FromDatePicker" $FromDatePicker.Text = "" #Label ToDate $labToDate.Location = New-Object System.Drawing.Point(5, 330) $labToDate.Name = "ToDate" $labToDate.Size = New-Object System.Drawing.Size(80, 40) $labToDate.Text = "To or less than" # ToDate Date Picker $ToDatePicker.DataBindings.DefaultDataSourceUpdateMode = 0 $ToDatePicker.Location = New-Object System.Drawing.Point(100, 330) $ToDatePicker.Name = "ToDatePicker" $ToDatePicker.Text = "" #Label Subject $labSubject.Location = New-Object System.Drawing.Point(5, 370) $labSubject.Size = New-Object System.Drawing.Size(50, 20) $labSubject.Name = "labSubject" $labSubject.Text = "Subject: " #TextBox Subject $txtBoxSubject.Location = New-Object System.Drawing.Point(100, 370) $txtBoxSubject.Size = New-Object System.Drawing.Size(280, 20) $txtBoxSubject.Name = "txtBoxSubject" $txtBoxSubject.Text = "" #Label FolderID $labFolderID.Location = New-Object System.Drawing.Point(5, 400) $labFolderID.Size = New-Object System.Drawing.Size(55, 20) $labFolderID.Name = "labFolderID" $labFolderID.Text = "FolderID:" #TextBox FolderID $txtBoxFolderID.Location = New-Object System.Drawing.Point(100, 400) $txtBoxFolderID.Size = New-Object System.Drawing.Size(280, 20) $txtBoxFolderID.Name = "txtBoxFolderID" $txtBoxFolderID.Text = "" #Adapting FolderID and TxtBoxFolderID based on the selection if ($radiobutton4.Checked -or $radiobutton5.Checked) { $labFolderID.Location = New-Object System.Drawing.Point(5, 285) $txtBoxFolderID.Location = New-Object System.Drawing.Point(100, 285) } elseif ($radiobutton8.Checked) { $labFolderID.Size = New-Object System.Drawing.Size(95, 20) $labFolderID.Text = "SourceFolderID:" } elseif ($radiobutton15.Checked) { $labFolderID.Location = New-Object System.Drawing.Point(5, 285) $labFolderID.Size = New-Object System.Drawing.Size(95, 20) $labFolderID.Text = "E-mail Address:" $txtBoxFolderID.Location = New-Object System.Drawing.Point(100, 285) } #Label Target FolderID $labTargetFolderID.Location = New-Object System.Drawing.Point(5, 430) $labTargetFolderID.Size = New-Object System.Drawing.Size(95, 20) $labTargetFolderID.Name = "labTargetFolderID" $labTargetFolderID.Text = "TargetFolderID:" #TextBox Target FolderID $txtBoxTargetFolderID.Location = New-Object System.Drawing.Point(100, 430) $txtBoxTargetFolderID.Size = New-Object System.Drawing.Size(280, 20) $txtBoxTargetFolderID.Name = "txtBoxTargetFolderID" $txtBoxTargetFolderID.Text = "" #Label TO recipients $labToRecipients.Location = New-Object System.Drawing.Point(5, 287) $labToRecipients.Size = New-Object System.Drawing.Size(25, 25) $labToRecipients.Name = "labToRecipients" $labToRecipients.Text = "To:" #TextBox TO recipients $txtBoxToRecipients.Location = New-Object System.Drawing.Point(95, 285) $txtBoxToRecipients.Size = New-Object System.Drawing.Size(280, 20) $txtBoxToRecipients.Name = "txtBoxToRecipients" $txtBoxToRecipients.Text = "" #Label CC Recipients $labCCRecipients.Location = New-Object System.Drawing.Point(5, 312) $labCCRecipients.Size = New-Object System.Drawing.Size(25, 25) $labCCRecipients.Name = "labCCRecipients" $labCCRecipients.Text = "Cc:" #TextBox CC recipients $txtBoxCCRecipients.Location = New-Object System.Drawing.Point(95, 310) $txtBoxCCRecipients.Size = New-Object System.Drawing.Size(280, 20) $txtBoxCCRecipients.Name = "txtBoxCCRecipients" $txtBoxCCRecipients.Text = "" #Label BCC Recipients $labBCCRecipients.Location = New-Object System.Drawing.Point(5, 337) $labBCCRecipients.Size = New-Object System.Drawing.Size(30, 25) $labBCCRecipients.Name = "labBCCRecipients" $labBCCRecipients.Text = "Bcc:" #TextBox BCC recipients $txtBoxBCCRecipients.Location = New-Object System.Drawing.Point(95, 335) $txtBoxBCCRecipients.Size = New-Object System.Drawing.Size(280, 20) $txtBoxBCCRecipients.Name = "txtBoxBCCRecipients" $txtBoxBCCRecipients.Text = "" #Label Mail Subject $labMailSubject.Location = New-Object System.Drawing.Point(5, 362) $labMailSubject.Size = New-Object System.Drawing.Size(50, 25) $labMailSubject.Name = "labMailSubject" $labMailSubject.Text = "Subject:" #TextBox Mail Subject $txtboxMailSubject.Location = New-Object System.Drawing.Point(95, 360) $txtboxMailSubject.Size = New-Object System.Drawing.Size(280, 20) $txtboxMailSubject.Name = "txtboxMailSubject" $txtboxMailSubject.Text = "" #Label Mail Body $labMailBody.Location = New-Object System.Drawing.Point(5, 387) $labMailBody.Size = New-Object System.Drawing.Size(45, 25) $labMailBody.Name = "labMailBody" $labMailBody.Text = "Body:" #TextBox Mail Body $txtboxMailBody.Location = New-Object System.Drawing.Point(95, 385) $txtboxMailBody.Size = New-Object System.Drawing.Size(280, 50) $txtboxMailBody.Name = "txtboxMailBody" $txtboxMailBody.Text = "" #Label Number of Messages $labNumOfMsgs.Location = New-Object System.Drawing.Point(5, 312) $labNumOfMsgs.Size = New-Object System.Drawing.Size(90, 28) $labNumOfMsgs.Name = "labNumOfMsgs" $labNumOfMsgs.Text = "# of Messages:" # NumericNumOfMsgs $NumericNumOfMsgs.DataBindings.DefaultDataSourceUpdateMode = 0 $NumericNumOfMsgs.Location = New-Object System.Drawing.Point(95, 310) $NumericNumOfMsgs.Size = New-Object System.Drawing.Size(40, 30) $NumericNumOfMsgs.Name = "NumericNumOfMsgs" $NumericNumOfMsgs.Minimum = 1 $NumericNumOfMsgs.Maximum = 9999 $NumericNumOfMsgs.Value = 1 # Label Use Attachment $UseAttachment.Location = New-Object System.Drawing.Point(5, 337) $UseAttachment.Size = New-Object System.Drawing.Size(110, 35) $UseAttachment.Name = "UseAttachment" $UseAttachment.Text = "Add attachment" # checkbox Use Attachment $checkboxUseAttachment.DataBindings.DefaultDataSourceUpdateMode = 0 $checkboxUseAttachment.Location = New-Object System.Drawing.Point(117, 335) $checkboxUseAttachment.Size = New-Object System.Drawing.Size(15, 20) $checkboxUseAttachment.Name = "checkboxUseAttachment" $checkboxUseAttachment.Checked = $false # Label Attachments warning $labAttachmentsWarning.Location = New-Object System.Drawing.Point(660, 82) $labAttachmentsWarning.Size = New-Object System.Drawing.Size(10, 20) $labAttachmentsWarning.Name = "labAttachmentsWarning" $labAttachmentsWarning.Font = New-Object System.Drawing.Font("Arial", 9, [System.Drawing.FontStyle]::Underline) $labAttachmentsWarning.ForeColor = "Blue" $labAttachmentsWarning.Text = "?" $labAttachmentsWarning.add_Click({ [Microsoft.VisualBasic.Interaction]::MsgBox("Injecting sample messages with no attachments should be pretty fast. But when using attachments, it might take considerable seconds.", [Microsoft.VisualBasic.MsgBoxStyle]::Okonly, "Information Message") }) $PremiseForm.Controls.Add($labAttachmentsWarning) # Picture box $pictureBox.Location = New-Object System.Drawing.Point(5, 317) $pictureBox.Size = New-Object System.Drawing.Size(140, 140) $pictureBox.Name = "PictureBox" # Button select new profile picture $buttonSelectPicture.DataBindings.DefaultDataSourceUpdateMode = 0 $buttonSelectPicture.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0) $buttonSelectPicture.Location = New-Object System.Drawing.Point(5, 287) $buttonSelectPicture.Size = New-Object System.Drawing.Size(200, 25) $buttonSelectPicture.Name = "buttonSelectPicture" $buttonSelectPicture.Text = "Select new picture" $buttonSelectPicture.UseVisualStyleBackColor = $True $buttonSelectPicture.add_Click({ $global:selectedProfilePicturePath = Select-ProfilePicture }) # Button Save new profile picture $buttonSavePicture.DataBindings.DefaultDataSourceUpdateMode = 0 $buttonSavePicture.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0) $buttonSavePicture.Location = New-Object System.Drawing.Point(210, 287) $buttonSavePicture.Size = New-Object System.Drawing.Size(200, 25) $buttonSavePicture.Name = "buttonSavePicture" $buttonSavePicture.Text = "Upload new picture" $buttonSavePicture.UseVisualStyleBackColor = $True $buttonSavePicture.add_Click({ Save-ProfilePicture -Account $Account -NewProfilePicture $selectedProfilePicturePath }) if ($radiobutton3.Checked) { $PremiseForm.Controls.Add($labFolderID) $PremiseForm.Controls.Add($txtBoxFolderID) $PremiseForm.Controls.Add($labFromDate) $PremiseForm.Controls.Add($FromDatePicker) $PremiseForm.Controls.Add($labToDate) $PremiseForm.Controls.Add($ToDatePicker) $PremiseForm.Controls.Add($labSubject) $PremiseForm.Controls.Add($txtBoxSubject) } elseif ($radiobutton4.Checked) { $labFolderID.Size = New-Object System.Drawing.Size(95, 20) $labFolderID.Text = "Folder Name:" $PremiseForm.Controls.Add($labFolderID) $PremiseForm.Controls.Add($txtBoxFolderID) } elseif ($radiobutton5.Checked) { $PremiseForm.Controls.Add($labFolderID) $PremiseForm.Controls.Add($txtBoxFolderID) } elseif ($radiobutton8.Checked) { $PremiseForm.Controls.Add($labFromDate) $PremiseForm.Controls.Add($FromDatePicker) $PremiseForm.Controls.Add($labToDate) $PremiseForm.Controls.Add($ToDatePicker) $PremiseForm.Controls.Add($labSubject) $PremiseForm.Controls.Add($txtBoxSubject) $PremiseForm.Controls.Add($labFolderID) $PremiseForm.Controls.Add($txtBoxFolderID) $PremiseForm.Controls.Add($labTargetFolderID) $PremiseForm.Controls.Add($txtBoxTargetFolderID) } elseif ($radiobutton9.Checked) { $PremiseForm.Controls.Add($labFromDate) $PremiseForm.Controls.Add($FromDatePicker) $PremiseForm.Controls.Add($labToDate) $PremiseForm.Controls.Add($ToDatePicker) $PremiseForm.Controls.Add($labSubject) $PremiseForm.Controls.Add($txtBoxSubject) $PremiseForm.Controls.Add($labFolderID) $PremiseForm.Controls.Add($txtBoxFolderID) } elseif ( $radiobutton11.Checked) { $PremiseForm.Controls.Add($labToRecipients) $PremiseForm.Controls.Add($txtBoxToRecipients) $PremiseForm.Controls.Add($labCCRecipients) $PremiseForm.Controls.Add($txtBoxCCRecipients) $PremiseForm.Controls.Add($labBCCRecipients) $PremiseForm.Controls.Add($txtBoxBCCRecipients) $PremiseForm.Controls.Add($labMailSubject) $PremiseForm.Controls.Add($txtboxMailSubject) $PremiseForm.Controls.Add($labMailBody) $PremiseForm.Controls.Add($txtboxMailBody) } elseif ( $radiobutton12.Checked) { $PremiseForm.Controls.Add($labToRecipients) $PremiseForm.Controls.Add($txtBoxToRecipients) $PremiseForm.Controls.Add($labNumOfMsgs) $PremiseForm.Controls.Add($NumericNumOfMsgs) $PremiseForm.Controls.Add($labMailSubject) $PremiseForm.Controls.Add($txtboxMailSubject) $PremiseForm.Controls.Add($labMailBody) $PremiseForm.Controls.Add($txtboxMailBody) $PremiseForm.Controls.Add($UseAttachment) $PremiseForm.Controls.Add($checkboxUseAttachment) } elseif ($radiobutton13.Checked) { $pictureBox.Image = $null $PremiseForm.Controls.Add($pictureBox) } elseif ($radiobutton14.Checked) { $pictureBox.Image = $null $PremiseForm.Controls.Add($pictureBox) $PremiseForm.Controls.Add($buttonSelectPicture) $PremiseForm.Controls.Add($buttonSavePicture) } elseif ($radiobutton15.Checked) { $PremiseForm.Controls.Add($labFolderID) $PremiseForm.Controls.Add($txtBoxFolderID) } $PremiseForm.refresh() } $OnLoadMainWindow_StateCorrection = { #Correct the initial state of the form to prevent the .Net maximized form issue $PremiseForm.WindowState = $InitialFormWindowState } #---------------------------------------------- #region Generated Form Code $PremiseForm.Controls.Add($radiobutton1) $PremiseForm.Controls.Add($radiobutton2) $PremiseForm.Controls.Add($radiobutton3) $PremiseForm.Controls.Add($radiobutton4) $PremiseForm.Controls.Add($radiobutton5) $PremiseForm.Controls.Add($radiobutton6) $PremiseForm.Controls.Add($radiobutton7) $PremiseForm.Controls.Add($radiobutton8) $PremiseForm.Controls.Add($radiobutton9) $PremiseForm.Controls.Add($radiobutton10) $PremiseForm.Controls.Add($radiobutton11) $PremiseForm.Controls.Add($radiobutton12) $PremiseForm.Controls.Add($radiobutton13) $PremiseForm.Controls.Add($radiobutton14) if ( $null -eq $service.Account ) { $PremiseForm.Controls.Add($radiobutton15) } $PremiseForm.Controls.Add($buttonGo) $PremiseForm.Controls.Add($buttonExit) $statusBar = New-Object System.Windows.Forms.StatusStrip $statusBar.Name = "statusBar" $statusBarLabel = New-Object System.Windows.Forms.ToolStripStatusLabel $null = $statusBar.Items.Add($statusBarLabel) $statusBarLabel.Text = "Ready..." $PremiseForm.Controls.Add($statusBar) $PremiseForm.ClientSize = New-Object System.Drawing.Size(850, 720) $PremiseForm.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $PremiseForm.Name = "form1" $PremiseForm.Text = "Managing user: $Account. Choose your Option" $PremiseForm.StartPosition = "CenterScreen" $PremiseForm.KeyPreview = $True $PremiseForm.Add_KeyDown({ if ($_.KeyCode -eq "Escape") { Get-ChildItem -Path "$env:temp\profilephoto*" | Remove-Item -Force -ErrorAction SilentlyContinue $PremiseForm.Close() return } }) # # radiobutton1 # $radiobutton1.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton1.Location = New-Object System.Drawing.Point(20, 20) $radiobutton1.Size = New-Object System.Drawing.Size(300, 20) $radiobutton1.Text = "1 - List Folders in Root" $radioButton1.Checked = $true $radiobutton1.UseVisualStyleBackColor = $True $radiobutton1.Add_Click({ & $ExpandFilters }) # # radiobutton2 # $radiobutton2.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton2.Location = New-Object System.Drawing.Point(20, 50) $radiobutton2.Size = New-Object System.Drawing.Size(300, 20) $radiobutton2.Text = "2 - List folders in Recoverable Items Root folder" $radioButton2.Checked = $false $radiobutton2.UseVisualStyleBackColor = $True $radiobutton2.Add_Click({ & $ExpandFilters }) # # radiobutton3 # $radiobutton3.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton3.Location = New-Object System.Drawing.Point(20, 80) $radiobutton3.Size = New-Object System.Drawing.Size(300, 20) $radiobutton3.Text = "3 - List Items in a desired Folder" $radiobutton3.Checked = $false $radiobutton3.UseVisualStyleBackColor = $True $radiobutton3.Add_Click({ & $ExpandFilters }) # # radiobutton4 # $radiobutton4.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton4.Location = New-Object System.Drawing.Point(20, 110) $radiobutton4.Size = New-Object System.Drawing.Size(300, 20) $radiobutton4.Text = "4 - Create a custom Folder in Root" $radiobutton4.Checked = $false $radiobutton4.UseVisualStyleBackColor = $True $radiobutton4.Add_Click({ & $ExpandFilters }) # # radiobutton5 # $radiobutton5.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton5.Location = New-Object System.Drawing.Point(20, 140) $radiobutton5.Size = New-Object System.Drawing.Size(300, 20) $radiobutton5.Text = "5 - Delete a Folder" $radiobutton5.Checked = $false $radiobutton5.UseVisualStyleBackColor = $True $radiobutton5.Add_Click({ & $ExpandFilters }) # # radiobutton6 # $radiobutton6.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton6.Location = New-Object System.Drawing.Point(20, 170) $radiobutton6.Size = New-Object System.Drawing.Size(300, 20) $radiobutton6.Text = "6 - Get user's Inbox Rules" $radiobutton6.Checked = $false $radiobutton6.UseVisualStyleBackColor = $True $radiobutton6.Add_Click({ & $ExpandFilters }) # # radiobutton7 # $radiobutton7.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton7.Location = New-Object System.Drawing.Point(20, 200) $radiobutton7.Name = "radiobutton7" $radiobutton7.Size = New-Object System.Drawing.Size(300, 20) $radiobutton7.Text = "7 - Get user's OOF Settings" $radiobutton7.Checked = $false $radiobutton7.UseVisualStyleBackColor = $True $radiobutton7.Add_Click({ & $ExpandFilters }) # # radiobutton8 # $radiobutton8.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton8.Location = New-Object System.Drawing.Point(20, 230) $radiobutton8.Size = New-Object System.Drawing.Size(300, 20) $radiobutton8.Text = "8 - Move items between folders" $radiobutton8.Checked = $false $radiobutton8.UseVisualStyleBackColor = $True $radiobutton8.Add_Click({ & $ExpandFilters }) # # radiobutton9 # $radiobutton9.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton9.Location = New-Object System.Drawing.Point(20, 260) $radiobutton9.Size = New-Object System.Drawing.Size(300, 20) $radiobutton9.TabIndex = 9 $radiobutton9.Text = "9 - Delete a subset of items in a folder" $radiobutton9.Checked = $false $radiobutton9.UseVisualStyleBackColor = $True $radiobutton9.Add_Click({ & $ExpandFilters }) # # radiobutton10 # $radiobutton10.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton10.Location = New-Object System.Drawing.Point(400, 20) $radiobutton10.Size = New-Object System.Drawing.Size(300, 20) $radiobutton10.Text = "10 - Get user's Delegate information" $radiobutton10.Checked = $false $radiobutton10.UseVisualStyleBackColor = $True $radiobutton10.Add_Click({ & $ExpandFilters }) # # radiobutton11 # $radiobutton11.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton11.Location = New-Object System.Drawing.Point(400, 50) $radiobutton11.Size = New-Object System.Drawing.Size(300, 20) $radiobutton11.Text = "11 - Send mail message" $radiobutton11.Checked = $false $radiobutton11.UseVisualStyleBackColor = $True $radiobutton11.Add_Click({ & $ExpandFilters }) # # radiobutton12 # $radiobutton12.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton12.Location = New-Object System.Drawing.Point(400, 80) $radiobutton12.Size = New-Object System.Drawing.Size(260, 20) $radiobutton12.Text = "12 - Inject mail messages into 'Inbox' folder" $radiobutton12.Checked = $false $radiobutton12.UseVisualStyleBackColor = $True $radiobutton12.Add_Click({ & $ExpandFilters }) # # radiobutton13 # $radiobutton13.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton13.Location = New-Object System.Drawing.Point(400, 110) $radiobutton13.Size = New-Object System.Drawing.Size(300, 20) $radiobutton13.Text = "13 - Get profile photo" $radiobutton13.Checked = $false $radiobutton13.UseVisualStyleBackColor = $True $radiobutton13.Add_Click({ & $ExpandFilters }) # # radiobutton14 # $radiobutton14.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton14.Location = New-Object System.Drawing.Point(400, 140) $radiobutton14.Size = New-Object System.Drawing.Size(300, 20) $radiobutton14.Text = "14 - Upload profile photo" $radiobutton14.Checked = $false $radiobutton14.UseVisualStyleBackColor = $True $radiobutton14.Add_Click({ & $ExpandFilters }) # # radiobutton15 # $radiobutton15.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton15.Location = New-Object System.Drawing.Point(400, 170) $radiobutton15.Size = New-Object System.Drawing.Size(300, 20) $radiobutton15.Text = "15 - Switch to another Mailbox:" $radiobutton15.Checked = $false $radiobutton15.UseVisualStyleBackColor = $True $radiobutton15.Add_Click({ & $ExpandFilters }) # # radiobutton16 # $radiobutton16.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation $radiobutton16.Location = New-Object System.Drawing.Point(400, 200) $radiobutton16.Size = New-Object System.Drawing.Size(190, 20) $radiobutton16.Text = "16" $radiobutton16.Checked = $false $radiobutton16.UseVisualStyleBackColor = $True $radiobutton16.Add_Click({ & $ExpandFilters }) #"Go" button $buttonGo.DataBindings.DefaultDataSourceUpdateMode = 0 $buttonGo.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0) $buttonGo.Location = New-Object System.Drawing.Point(700, 20) $buttonGo.Size = New-Object System.Drawing.Size(50, 25) $buttonGo.Name = "Go" $buttonGo.Text = "Go" $buttonGo.UseVisualStyleBackColor = $True $buttonGo.add_Click({ if ($radiobutton1.Checked) { Get-FolderList -Account $Account } elseif ($radiobutton2.Checked) { Get-FolderList -Account $Account } elseif ($radiobutton3.Checked) { Get-ItemsInFolder -Account $Account -FolderId $txtBoxFolderID.Text -StartDate $FromDatePicker.Value.ToString("yyyy-MM-dd") -EndDate $ToDatePicker.Value.ToString("yyyy-MM-dd") -MsgSubject $txtBoxSubject.Text } elseif ($radiobutton4.Checked) { New-CustomFolder -Account $Account -DisplayName $txtBoxFolderID.Text } elseif ($radiobutton5.Checked) { Remove-SpecificFolder -Account $Account -Folderid $txtBoxFolderID.Text } elseif ($radiobutton6.Checked) { Get-UserInboxRule -Account $Account } elseif ($radiobutton7.Checked) { Get-UserOOFSettings -Account $Account } elseif ($radiobutton8.Checked) { Move-ItemsBetweenFolder -Account $Account -FolderId $txtBoxFolderID.Text -TargetFolderID $txtBoxTargetFolderID.Text -StartDate $FromDatePicker.Value.ToString("yyyy-MM-dd") -EndDate $ToDatePicker.Value.ToString("yyyy-MM-dd") -MsgSubject $txtBoxSubject.Text } elseif ($radiobutton9.Checked) { Remove-ItemsInFolder -Account $Account -FolderId $txtBoxFolderID.Text -StartDate $FromDatePicker.Value.ToString("yyyy-MM-dd") -EndDate $ToDatePicker.Value.ToString("yyyy-MM-dd") -MsgSubject $txtBoxSubject.Text } elseif ($radiobutton10.Checked) { Get-UserDelegates -Account $Account } elseif ($radiobutton11.Checked) { Send-GraphEmailMessage -Account $Account -ToRecipients $txtBoxToRecipients.Text -CCRecipients $txtBoxCCRecipients.Text -BCCRecipients $txtBoxBCCRecipients.text -Subject $txtboxMailSubject.Text -Body $txtboxMailBody.Text } elseif ($radiobutton12.Checked) { New-EmailInInbox -Account $Account -ToRecipients $txtBoxToRecipients.Text -Subject $txtboxMailSubject.Text -Body $txtboxMailBody.Text -NumberOfMessages $NumericNumOfMsgs.Value -UseAttachment:$checkboxUseAttachment.Checked } elseif ($radiobutton13.Checked) { Get-UserProfilePicture -Account $Account } elseif ($radiobutton14.Checked) { } elseif ($radiobutton15.Checked) { $Global:Account = Switch-AnotherMailbox -Account $txtBoxFolderID.Text } }) #"Exit" button $buttonExit.DataBindings.DefaultDataSourceUpdateMode = 0 $buttonExit.ForeColor = [System.Drawing.Color]::FromArgb(255, 0, 0, 0) $buttonExit.Location = New-Object System.Drawing.Point(700, 50) $buttonExit.Size = New-Object System.Drawing.Size(50, 25) $buttonExit.Name = "Exit" $buttonExit.Text = "Exit" $buttonExit.UseVisualStyleBackColor = $True $buttonExit.add_Click({ Get-ChildItem -Path "$env:temp\profilephoto*" | Remove-Item -Force -ErrorAction SilentlyContinue $PremiseForm.Close() return }) #TextBox results $txtBoxResults.DataBindings.DefaultDataSourceUpdateMode = 0 $txtBoxResults.Location = New-Object System.Drawing.Point(5, 460) $txtBoxResults.Size = New-Object System.Drawing.Size(840, 240) $txtBoxResults.Name = "TextResults" $txtBoxResults.BackColor = [System.Drawing.Color]::White $txtBoxResults.BorderStyle = [System.Windows.Forms.BorderStyle]::Fixed3D $txtBoxResults.Font = New-Object System.Drawing.Font("Consolas", 8) $PremiseForm.Controls.Add($txtBoxResults) #dataGrid $dgResults.Anchor = 15 $dgResults.DataBindings.DefaultDataSourceUpdateMode = 0 $dgResults.DataMember = "" $dgResults.Location = New-Object System.Drawing.Point(5, 460) $dgResults.Size = New-Object System.Drawing.Size(840, 240) $dgResults.Name = "dgResults" $dgResults.ReadOnly = $True $dgResults.RowHeadersVisible = $False $dgResults.Visible = $False $dgResults.AllowUserToOrderColumns = $True $dgResults.AllowUserToResizeColumns = $True $PremiseForm.Controls.Add($dgResults) #endregion Generated Form Code # Show Form #Save the initial state of the form $InitialFormWindowState = $PremiseForm.WindowState #Init the OnLoad event to correct the initial state of the form $PremiseForm.add_Load($OnLoadMainWindow_StateCorrection) $PremiseForm.Add_Shown({ $PremiseForm.Activate() }) $PremiseForm.ShowDialog() | Out-Null } #End Function #Call the Function try { GenerateForm } finally { Stop-ModuleUpdate -RunspaceData $runspaceData } } <# This is an example configuration file By default, it is enough to have a single one of them, however if you have enough configuration settings to justify having multiple copies of it, feel totally free to split them into multiple files. #> <# # Example Configuration Set-PSFConfig -Module 'ExoGraphGUI' -Name 'Example.Setting' -Value 10 -Initialize -Validation 'integer' -Handler { } -Description "Example configuration setting. Your module can then use the setting using 'Get-PSFConfigValue'" #> Set-PSFConfig -Module 'ExoGraphGUI' -Name 'Import.DoDotSource' -Value $false -Initialize -Validation 'bool' -Description "Whether the module files should be dotsourced on import. By default, the files of this module are read as string value and invoked, which is faster but worse on debugging." Set-PSFConfig -Module 'ExoGraphGUI' -Name 'Import.IndividualFiles' -Value $false -Initialize -Validation 'bool' -Description "Whether the module files should be imported individually. During the module build, all module code is compiled into few files, which are imported instead by default. Loading the compiled versions is faster, using the individual files is easier for debugging and testing out adjustments." Set-PSFConfig -FullName PSFramework.Logging.FileSystem.ModernLog -Value $True -Validation 'bool' -Description "Enables the modern, more powereful version of the filesystem log, including headers and extra columns." -PassThru | Register-PSFConfig <# Stored scriptblocks are available in [PsfValidateScript()] attributes. This makes it easier to centrally provide the same scriptblock multiple times, without having to maintain it in separate locations. It also prevents lengthy validation scriptblocks from making your parameter block hard to read. Set-PSFScriptblock -Name 'ExoGraphGUI.ScriptBlockName' -Scriptblock { } #> <# # Example: Register-PSFTeppScriptblock -Name "ExoGraphGUI.alcohol" -ScriptBlock { 'Beer','Mead','Whiskey','Wine','Vodka','Rum (3y)', 'Rum (5y)', 'Rum (7y)' } #> <# # Example: Register-PSFTeppArgumentCompleter -Command Get-Alcohol -Parameter Type -Name ExoGraphGUI.alcohol #> New-PSFLicense -Product 'ExoGraphGUI' -Manufacturer 'agallego' -ProductVersion $script:ModuleVersion -ProductType Module -Name MIT -Version "1.0.0.0" -Date (Get-Date "2023-01-10") -Text @" Copyright (c) 2023 agallego Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. "@ #endregion Load compiled code |