I'm developing a desktop app using jetpack compose which uses the windows toast notification feature a lot. I use PowerShell scripts to push the toast notification using BurntToast module. The notification works fine but, every time it gets executed, I see Windows Powershell as the app name and not any custom name.
PowerShell Notification Image:
How do I change the name from Windows PowerShell to my desired name?
# First, create all the component pieces
$AppLogo = New-BTImage -Source 'C:\Demos\img.jpg' -AppLogoOverride -Crop Circle
$HeroImage = New-BTImage -Source 'https://c.tenor.com/XfrqyR_-jzIAAAAC/anime-goku.gif' -HeroImage
$MapImage = New-BTImage -Source 'https://media.giphy.com/media/WW33vGSPHXym7Wh80e/giphy.gif'
$TextHeading = New-BTText -Text 'Lord Shiva'
$TextBody = New-BTText -Text 'The mightiest god there is!'
# Then bind them together
$Binding = New-BTBinding -Children $TextHeading, $TextBody, $MapImage -AppLogoOverride $AppLogo -HeroImage $HeroImage
# And remember that these components are visual, but not actionable
$Visual = New-BTVisual -BindingGeneric $Binding
# Speaking of actionable, we're using actions right?
$GoogleButton = New-BTButton -Content 'Google Maps' -Arguments 'https://www.google.com/maps/SNIP'
$BingButton = New-BTButton -Content 'Bing Maps' -Arguments 'https://www.bing.com/maps?SNIP'
# Don't forget that an action by itself is useless, even a single button needs to become plural
$Actions = New-BTAction -Buttons $GoogleButton, $BingButton
# Now all of the content is together...
$Content = New-BTContent -Visual $Visual -Actions $Actions
# We can submit it to the Operating System
Submit-BTNotification -Content $Content
Related
So my organization has tasked me with cleaning up some of the security issues in regards to some automated scripts that have hard coded passwords within the scripts that are running as automated tasks. One such task contains SFTP scripts that export and import files to and from with the password, host name, credentials, port, and everything exposed within the script. As a result, I would like to first see about how to call such credentials within a separate file that can be hidden and two see about encryption and salting it later. But my main focus is getting them out of the script in case traffic is every intercepted. Here is what the PowerShell code looks like:
param (
$localPath = 'E:\FTP\SchooLinks\course_requests.csv',
$remotePath = '/schoolinks_exports/course_planning/course_requests.csv'
)
try
{
# Load WinSCP .NET assembly
Add-Type -Path "C:\Program Files (x86)\WinSCP\WinSCPnet.dll"
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Sftp
HostName = "<domain_name>"
UserName = "<username>"
Password = "<password>"
SshHostKeyFingerprint = "<fingerprint>"
}
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
# Upload files
$transferOptions = New-Object WinSCP.TransferOptions
$transferOptions.TransferMode = [WinSCP.TransferMode]::Binary
$transferResult =
$session.GetFiles($remotePath, $localPath, $False, $transferOptions)
# Throw on any error
$transferResult.Check()
# Print results
foreach ($transfer in $transferResult.Transfers)
{
Write-Host "Download of $($transfer.FileName) succeeded"
}
}
finally
{
# Disconnect, clean up
$session.Dispose()
}
exit 0
}
catch
{
Write-Host "Error: $($_.Exception.Message)"
exit 1
}
Another one that we have looks like this:
param (
$localPath = 'E:\FTP\TalentEd\SkywardApplicantExportSQL.txt',
$remotePath = '/SkywardApplicantExportSQL.txt'
)
try
{
# Load WinSCP .NET assembly
Add-Type -Path "C:\Program Files (x86)\WinSCP\WinSCPnet.dll"
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Sftp
HostName = "<domain>"
UserName = "<username>"
Password = "<password>"
SshHostKeyFingerprint = "<sha_fingerprint>"
}
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
# Upload files
$transferOptions = New-Object WinSCP.TransferOptions
$transferOptions.TransferMode = [WinSCP.TransferMode]::Binary
$transferResult =
$session.GetFiles($remotePath, $localPath, $False, $transferOptions)
# Throw on any error
$transferResult.Check()
# Print results
foreach ($transfer in $transferResult.Transfers)
{
Write-Host "Download of $($transfer.FileName) succeeded"
}
}
finally
{
# Disconnect, clean up
$session.Dispose()
}
exit 0
}
catch
{
Write-Host "Error: $($_.Exception.Message)"
exit 1
}
I am familiar with Python and json and calling stuff within a json file similar to the following:
import json
with open('secrets.json','r') as f:
config = json.load(f)
and calling it with (config['object']['nested_element']) within the Python script.
I would like to do something similar with PowerShell, however I have very limited knowledge to PowerShell.
Yeppers, of course, never store creds in clear text in files.
There are several ways to store credentials for use. Secure file (xml, etc..), the registry, or Windows Credential Manager and this is well documented on Microsoft sites, as well as in many articles all over the web and via Q&A's on StackOverflow.
Just search for 'securely store credentials PowerShell'
Sample results...
Working with Passwords, Secure Strings and Credentials in Windows
PowerShell
How to run a PowerShell script against multiple Active Directory
domains with different credentials
Accessing Windows Credentials Manager from PowerShell
Save Encrypted Passwords to Registry for PowerShell
...and/or the modules via the MS powershellgallery.com directly installable from your PowerShell environments.
Find-Module -Name '*cred*' |
Format-Table -AutoSize
<#
# Results
Version Name Repository Description
------- ---- ---------- -----------
2.0 CredentialManager PSGallery Provides access to credentials in the Windows Credential Manager
2.0.168 VcRedist PSGallery A module for lifecycle management of the Microsoft Visual C++ Redistributables. Downloads the supp...
1.3.0.0 xCredSSP PSGallery Module with DSC Resources for WSMan CredSSP.
1.1 VPNCredentialsHelper PSGallery A simple module to set the username and password for a VPN connection through PowerShell. Huge tha...
1.0.11 pscredentialmanager PSGallery This module allows management and automation of Windows cached credentials.
4.5 BetterCredentials PSGallery A (compatible) major upgrade for Get-Credential, including support for storing credentials in Wind...
1.0.4 WindowsCredential PSGallery Management module for Windows Credential Store.
...
#>
So many thanks to #postanote and #Martin Prikryl I was able to figure this out.
You can basically use a config.xml file with contents similar to this:
<Configuration>
<localPath>insert_local_file_path</localPath>
<remotePath>insert_remote_file_path</remotePath>
<Protocol>[WinSCP.Protocol]::Sftp</Protocol>
<HostName>insert_hostname</HostName>
<UserName>username</UserName>
<Password>mypassword</Password>
<SshHostKeyFingerPrint>fingerprint</SshHostKeyFingerPrint>
</Configuration>
From here you can use the following at the beginning of your template:
# Read XML configuration file
[xml]$config = Get-Content ".\config.xml"
param (
$localPath = $config.Configuration.localPath
$remotePath = $config.Configuration.remotePath
)
try
{
# Load WinSCP .NET assembly
Add-Type -Path "C:\Program Files (x86)\WinSCP\WinSCPnet.dll"
# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = $config.Configuration.Protocol
HostName = $config.Configuration.HostName
UserName = $config.Configuration.UserName
Password = $config.Configuration.Password
SshHostKeyFingerprint = $config.Configuration.SshHostKeyFingerprint
}
I have more SFTP templates here people can use at
https://github.com/Richard-Barrett/ITDataServicesInfra/tree/master/SFTP
the following powershell script successfully creates a notification but after the little popup retracts it doesn't show on the Notification Center, any way to leave it in the notification center until the user dismisses it ?
param([String]$prodName)
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null
[Windows.UI.Notifications.ToastNotification, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null
[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] > $null
$ToastTemplate = '
<toast launch="app-defined-string">
<visual>
<binding template="ToastGeneric">
<text>'+$prodName+'</text>
</binding>
</visual>
</toast>'
Write-Output $ToastTemplate;
$currTime = (Get-Date).AddSeconds(10);
"currTime : " + $currTime
$xml = New-Object Windows.Data.Xml.Dom.XmlDocument
$xml.LoadXml($toastXml.OuterXml)
$schedNotification = New-Object Windows.UI.Notifications.ToastNotification($xml)
$schedNotification.SuppressPopup = $True
$notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($prodName)
$notifier.Show($schedNotification)
$schedNotification = New-Object Windows.UI.Notifications.ScheduledToastNotification($xml, $currTime)
$notifier.AddToSchedule($schedNotification)
If you show your notification like this:
CreateToastNotifier("PowerShellAppId")
Then in your "Settings \ System \ Notifications & Actions", there should register new app named "PowerShellAppId".
Edit it, and select option "Show notifications in action center". If you run your script again, message should leave in notification panel.
In your example you have $prodName as AppID. So each time, you run script with different prodName, Windows will register it as separate entry, and you will have to set registry flag ("Show notifications in action center") again.
You can do it using PowerShell like this:
Set-ItemProperty "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Notifications\Settings\$prodName" -Name "ShowInActionCenter" -Type Dword -Value "1"
Consider using constant app name, something like NotificationManager to simplify things.
My organization uses a piece of software that has a printer name hard-coded into it PRN1.
Users are spread out through multiple locations; so it is impossible to just rename a single printer. Our networked printers are mapped by computer location via a login script; and some computers have locally attached printers.
The current proposed solution is to remote into each computer with the user logged in; re-map the users default printer; and manually rename it (Right click->Printer Prop...).
I'm trying to avoid this as we do not use roaming profiles and some users do move from location to location; and the users wouldn't understand why it suddenly isn't working.
Ideally I'd like to create a script that will automatically duplicate the users default printer; and name it PRN1.
$AllPrinters = gwmi win32_printer
$DefaultPrinter = $AllPrinters | where {$_.Default -eq $true}
rundll32 printui.dll,PrintUIEntry /ga /n $DefaultPrinter.SystemName + "\" + $DefaultPrinter.ShareName /z /b"PRN1"
Above is what I currently have; I know I'm not using the rundll32 command properly as the printer isn't being duplicated with the new name.
Any help or assistance would be greatly appreciated.
I use that rundll32 command here and there but never have solid luck with it.
You could do something like this by using wmi entirely. You may want to wrap a try catch around a large chunk of this to suppress errors and log output if users do end up having issues.
$Name = "PRN"
$AllPrinters = gwmi win32_printer
$DefaultPrinter = $AllPrinters | where {$_.Default -eq $true}
$objHelper = [WMICLASS]"\\localhost\root\cimv2:Win32_SecurityDescriptorHelper"
$print = [WMICLASS]"\\localhost\root\cimv2:Win32_Printer"
$print.Scope.Options.EnablePrivileges = $true
$newprinter = $print.createInstance()
$newprinter.drivername = $DefaultPrinter.DriverName
$newprinter.PortName = $DefaultPrinter.PortName
$newprinter.Shared = $false
$newprinter.Location = $DefaultPrinter.Location
$newprinter.Comment = $DefaultPrinter.Comment
$newprinter.DeviceID = $Name
$newprinter.PrintProcessor = $DefaultPrinter.PrintProcessor
$newprinter.PrintJobDataType = $DefaultPrinter.DataType
$newprinter.RawOnly = $DefaultPrinter.RawOnly
$result = $newprinter.Put()
I wrote a Powershell script that uses the Windows Update Agent API (IUpdateSearcher, IUpdateDownloader, IUpdateInstaller etc.). Everything works fine, the script finds avaiable updates, downloads and installs them.
However, there is a problem when searching for consecutive updates. For example, there is an update for the .Net Framework 4.5.2. The update is installed by script and the PC is rebooted afterwards. Now there should be an update for the .Net Framework 4.5.2 Language Pack avaiable.
But it is not. At least not via the API. A manual search with the GUI (Windows Update) works.
After the manual search, the API finds the update a well!
What am I missing in my script? I could not find anything in Microsofts documentation: https://msdn.microsoft.com/en-us/library/windows/desktop/aa386868(v=vs.85).aspx
$updateSession = New-Object -ComObject 'Microsoft.Update.Session'
$UpdateSession.WebProxy.AutoDetect = $false
$updateSearcher = $updateSession.CreateUpdateSearcher()
$searchResult = $updateSearcher.Search('IsInstalled=0 and IsHidden=0')
$objCollectionDownload = New-Object -ComObject 'Microsoft.Update.UpdateColl'
foreach ($update in $searchResult.Updates)
{
$objCollectionTmp = New-Object -ComObject 'Microsoft.Update.UpdateColl'
$objCollectionTmp.Add($update) | Out-Null
$downloader = $updateSession.CreateUpdateDownloader()
$downloader.Updates = $objCollectionTmp
try
{
$downloadResult = $downloader.Download()
}
catch
{
//exception Handling
}
$objCollectionDownload.Add($update) | Out-Null
}
$updatesToInstall = New-Object -ComObject 'Microsoft.Update.UpdateColl'
$updateInstaller = $updateSession.CreateUpdateInstaller()
foreach ($update in $objCollectionDownload)
{
//accept Eula etc...
$updatesToInstall.Add($update) | Out-Null
}
$updateInstaller.Updates = $updatesToInstall
$installationRestult = $updateInstaller.Install()
//check installation result
Oddly enough I had the same issue just now, Windows GUI showed a particular update, Our GUI using the API wouldn't show this particular update... I had IsInstalled = 0 and IsHidden = 0.... I looked in the WIndows Update log and found the criteria that the WIndows GUI was using.
IsInstalled=0 and DeploymentAction='Installation' or IsPresent=1 and DeploymentAction='Uninstallation' or IsInstalled=1 and DeploymentAction='Installation' and RebootRequired=1 or IsInstalled=0 and DeploymentAction='Uninstallation' and RebootRequired=1
Added this to my application in place of IsInstalled = 0 and IsHidden = 0 and the update showed straight up :-/ don't really understand why but I am not complaining.
I've run into a small problem with a script I've been working on.
The code itself works perfectly fine; when I run it on my local workstation, it's perfect. However, when I run it on one of the servers (Win 2003 R2 32-bit) that need SCCM installed on it (which this script is designed to automatically install) it fails in one of my functions. Relevent code follows:
# Schedules Weekly tasks
function SchWeekly
{param ([string]$Comp, [string]$Date, [string]$RunTime, [int]$DayOfWeek, [string] $commandpath)
$service = new-object -comobject "Schedule.Service" # Forms object reference
$service.Connect($Comp) # Connects to host machine
$rootFolder = $service.GetFolder("\") # Sets root folder of Task Scheduler
$taskDefinition = $service.NewTask(0) # Begins task creation
$regInfo = $taskDefinition.RegistrationInfo # Sets registry info
$regInfo.Description = 'SCCM Check For Update'
$regInfo.Author = "Administrator"
$settings=$taskDefinition.Settings # Sets default settings for the new task
$settings.StartWhenAvailable = $True
$settings.Hidden = $False
$triggers = $taskDefinition.Triggers # Creates Trigger object reference
$trigger = $triggers.Create(3) # Sets to create (Number 3 means Weekly trigger)
# Start Time ex. 2012-6-10 22:00:00
$trigger.StartBoundary = $Date + "T" + $RunTime # Sets start date (End date can be set) e
# ex. $trigger.EndBoundary = Date + "T" + Time
$trigger.DaysOfWeek = $DayOfWeek # Sends integer for day of week to run on (1-7)
# 1 = Sunday, 2 = Monday, etc....
$trigger.WeeksInterval = 1 # Sets to run every week
$trigger.Id = "WeeklyTriggerId" # Trigger ID name
$trigger.Enabled = $True
$Action = $taskDefinition.Actions.Create(0)
$Action.Path = $commandpath # Links to script
$rootFolder.RegisterTaskDefinition('SCCM Check For Update', $taskDefinition, 6, "", "", 3) # Registers scheduled task
}
The error specifically is on this line:
$service = new-object -comobject "Schedule.Service"
It reports that "Cannot load COM type Schedule.Service"
The reason is your local box is widows 7 server 2003 does not have the comobject "Schedule.Service" it is part of windows 7 and 2008.
If you follow the link below it will show you how to schedule a task on a windows 2003 server using powershell.
Schedules tasks on w2k3