Remote Powershell Popup message to all users not working - powershell

I'm having some issues creating a remote powershell popup message.
I've got a working script that displays the popup message that I want to send to a remote user. However, whenever I bundle it up in a .ps1 script and run it remotely it does not send a popup message to the logged in user. I know the script is running correctly, as I have other parts of the script that execute correctly. I was able to run the popup message on a local machine, so it is not a script error.
The script is:
Add-Type -AssemblyName System.Windows.Forms
$Form = New-Object system.Windows.Forms.Form
$Form.Text = 'ALERT!'
$form.ControlBox = $false;
$Image = [system.drawing.image]::FromFile('\\filepath')
$Form.BackgroundImage = $Image
$Form.BackgroundImageLayout = 'Stretch'
$Form.Width = (680)
$Form.Height = (550)
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(500,445)
$OKButton.Size = New-Object System.Drawing.Size(100,50)
$OKButton.Text = 'Accept'
$OKButton.Font = New-Object System.Drawing.Font('Times New Roman',18)
$OKButton.Add_Click({$Form.Close()})
$Form.Controls.Add($OKButton)
$Form.Add_Shown({$Form.Activate()})
[void] $Form.ShowDialog()
I'm running this as part of a .ps1 that is called in the following fashion:
Invoke-WmiMethod -Class Win32_Process -ComputerName $computer -Name Create -ArgumentList "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe \\$computer\C$\folder\script.ps1
I'm running the script as a service account from a server that's executing the commands on a Windows 7 enterprise desktop machine. The target machine execution policy is set to unrestricted so I know it is not a script execution policy issue.
I have a hunch that the reason that it is not popping up on the target machine is because the account that is running the script and the account that is logged into the target machine are different, however I could be incorrect.

Your hunch is correct. The PowerShell script is running in the context of the service account, and won't show up for any of the logged in users. (for ex. if your script launched notepad.exe, it would run only for the service account).
You will see it pop up when you run the command locally under the same account.
#Adrian R is correct you can use msg.exe to send a message, or the more commandline friendly:
net send /users message
If you want to show something more complex (i.e. a full-on Windows form) instead of the classic message box, then you need to be running something in the user context. One way to do this is to use PsExec with the -i (interactive option) instead of using PowerShell remoting.

Related

PowerShell - Connect and disconnect from SPO

The script connects to SPO and read from excel. At the end I close the local excel instance and disconnect from SPO. Usually I am running the script so this is really necessary to do it every run? connect ad disconnect. Maybe there is another way to do it? ask if there is a valid active connection?
I saw that if the credentials are wrong for example the script is still reading from the sheet maybe from the memory, how can I protect from this scenario?
#Connecting to SharePoint Online site
Write-host "Connecting to SharePoint Online"
Connect-PnPOnline -Url $SharePointSiteURL # -Credentials $PSCredentials
$ExcelObject = New-Object -ComObject Excel.Application
$ExcelWorkBook = $ExcelObject.Workbooks.Open($SharePointSiteURL)
$ExcelWorkSheet = $ExcelWorkBook.Sheets.Item("VIP List")
function QuitExcel {
# when done, quit Excel and remove the used COM objects from memory (important)
$ExcelWorkBook.Close()
$ExcelObject.Quit()
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelWorkSheet)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelWorkBook)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelObject)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
Disconnect-PnPOnline

Invoke-DbaQuery -SqlCredential works interactively, but not when called from web app

I have a powershell script that I am calling from a Visual Studio web app (C#). I have an app pool set up, and the script executes. However, when I use any Invoke-DbaQuery command using the -SqlCredential, it works just fine from the powershell console, but it uses the app pool creds when called from the web app.
Here is some test code:
$mytest = Invoke-DbaQuery -SqlInstance $BackupInstance -Database "master" -SqlCredential $SourceCredential -Query "select suser_name()" -as SingleValue
write-output "I am currently running as: $mytest"
From powershell, this returns:
I am currently running as: MYDOMAIN\myAdUserName
When I run it through the web app I get:
I am currently running as: MYDOMAIN\AppPoolServerName$
I have changed my credentials to try a different user, and it returns that new user when ran from console, but still the machine name when ran from Web.
Any ideas why this is happening and how to fix?
Edit: $SourceCredential is being set as follows:
$SourceUsername = 'MYDOMAIN\MyAdUserName' $SecureIntPw = Get-Content "C:\Scripts\Security\MyAdUserName.txt" | ConvertTo-SecureString $SourceCredential = new-object -typename System.Management.Automation.PSCredential -argumentlist $SourceUserName, $SecureIntPw

How to run Powershell script on local computer but with credentials of a domain user

I have to implement a solution where I have to deploy a SSIS project (xy.ispac) from one machine to another. So far I've managed to copy-cut-paste the following stuff from all around the internet:
# Variables
$ServerName = "target"
$SSISCatalog = "SSISDB" # sort of constant
$CatalogPwd = "catalog_password"
$ProjectFilePath = "D:\Projects_to_depoly\Project_1.ispac"
$ProjectName = "Project_name"
$FolderName = "Data_collector"
# Load the IntegrationServices Assembly
[Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Management.IntegrationServices")
# Store the IntegrationServices Assembly namespace to avoid typing it every time
$ISNamespace = "Microsoft.SqlServer.Management.IntegrationServices"
Write-Host "Connecting to server ..."
# Create a connection to the server
$sqlConnectionString = "Data Source=$ServerName;Initial Catalog=master;Integrated Security=SSPI;"
$sqlConnection = New-Object System.Data.SqlClient.SqlConnection $sqlConnectionString
$integrationServices = New-Object "$ISNamespace.IntegrationServices" $sqlConnection
$catalog = $integrationServices.Catalogs[$SSISCatalog]
# Create the Integration Services object if it does not exist
if (!$catalog) {
# Provision a new SSIS Catalog
Write-Host "Creating SSIS Catalog ..."
$catalog = New-Object "$ISNamespace.Catalog" ($integrationServices, $SSISCatalog, $CatalogPwd)
$catalog.Create()
}
$folder = $catalog.Folders[$FolderName]
if (!$folder)
{
#Create a folder in SSISDB
Write-Host "Creating Folder ..."
$folder = New-Object "$ISNamespace.CatalogFolder" ($catalog, $FolderName, $FolderName)
$folder.Create()
}
# Read the project file, and deploy it to the folder
Write-Host "Deploying Project ..."
[byte[]] $projectFile = [System.IO.File]::ReadAllBytes($ProjectFilePath)
$folder.DeployProject($ProjectName, $projectFile)
This seemed to be working surprisingly well on the development machine - test server pair. However, the live environment will be a bit different, the machine doing the deployment job (deployment server, or DS from now on) and the SQL Server (DB for short) the project is to be deployed are in different domains and since SSIS requires windows authentication, I'm going to need to run the above code locally on DS but using credentials of a user on the DB.
And that's the point where I fail. The only thing that worked is to start the Powershell command line interface using runas /netonly /user:thatdomain\anuserthere powershell, enter the password, and paste the script unaltered into it. Alas, this is not an option, since there's no way to pass the password to runas (at least once with /savecred) and user interactivity is not possible anyway (the whole thing has to be automated).
I've tried the following:
Simply unning the script on DS, the line $sqlConnection = New-Object System.Data.SqlClient.SqlConnection $sqlConnectionString would use the credentials from DS which is not recognized by DB, and New-Object does not have a -Credential arg that I could pass to
Putting everything into an Invoke-Command with -Credential requires using -Computername as well. I guess it would be possible to use the local as 'remote' (using . as Computername) but it still complains about access being denied. I'm scanning through about_Remote_Troubleshooting, so far without any success.
Any hints on how to overcome this issue?
A solution might be to use a sql user (with the right access rights) instead of an AD used.
Something like this should work.
(Check also the answer to correct the connection string)

cmdkey in PowerShell doesn't work when run as a logon script?

Trying is use cmdkey in a PowerShell logon script to store credentials in the credential manager. When the script is run from PowerShell ISE everything works, but when it's run as a logon script via Group Policy everything but cmdkey works. Cannot for the life of me figure out why cmdkey will work everywhere except when the script run on logon.
# Checks if CRM for Outlook is isntalled by checking the folder path
$installed = Test-Path "C:\Program Files (x86)\Microsoft Dynamics CRM"
# Checks if the CRM has already been configured using the CoreConfigured registry entry
$configured = Get-ItemProperty -Path HKCU:\software\Microsoft\MSCRMClient -Name "CoreConfigured"
# If CRM is installed and not configured, configure it, if CRM is not installed or installed and configured, exit
If ($installed -eq "True" -and $configured.CoreConfigured -ne 1) {
$message1 = New-object -ComObject Wscript.Shell
$message1.Popup("Preparing to configure Microsoft CRM for Outlook, please make sure Outlook is closed.",10,"Systems")
# Prompts user for email address and Password to configure CRM for Outlook
$c = Get-Credential -Message "To confgiure CRM, please enter your email address and password:"
# puts user credentials into Windows Credential Manager using required CRM URLs
cmdkey /generic:Microsoft_CRM_https://disco.crm.dynamics.com/ /user: $c.Username /pass: $c.Password | Out-Null
cmdkey /generic:Microsoft_CRM_https://disco.crm4.dynamics.com/ /user: $c.Username /pass: $c.Password | Out-Null
$message2 = New-Object -ComObject Wscript.Shell
$message2.Popup("Please wait, a notification will appear when the configuration is complete.",10,"Systems")
# Silenty runs the CRM configuration Wizard with custom XML file
$exe = "C:\Program Files (x86)\Microsoft Dynamics CRM\Client\ConfigWizard\Microsoft.Crm.Application.Outlook.ConfigWizard.exe"
&$exe -p /Q /i 'C:\Program Files (x86)\Microsoft Dynamics CRM\Default_Client_Config.xml' /xa /l 'c:\temp\crminstall.txt' | Out-Null
$message3 = New-Object -ComObject Wscript.Shell
$message3.Popup("Configuration complete! You may now open Outlook!",10,"Systems")
}
else {
exit
}
I imagine cmdkey is using Microsoft's Data Protection API (DPAPI) to encrypt credentials so only the current user can retrieve them. You can't use this API unless the user's session is loaded. When your script runs, it may be too early in the logon process for the security information the DPAPI needs is loaded. I'm not sure how logon scripts work, but try putting a delay in your logon script until you get a value back.
Here's the PowerShell code that encrypts with the DPAPI:
$scope = [Security.Cryptography.DataProtectionScope]::CurrentUser
$encryptedBytes = [Security.Cryptography.ProtectedData]::Protect( $plainBytes, $null, $scope )
$decryptedBytes = [Security.Cryptography.ProtectedData]::Unprotect( $encryptedBytes, $null, 0 )
Add a loop in your logn script that tries to encrypt/decrypt some random array of bytes until it succeeds.
I had the same issue: cmdkey was not working in Powershell when run as a User Logon Script.
In my case the issue was related to the user's group membership. The user was a member of the group "Power Users", but not a member of the group "Users" (or any other group).
According to this article from Microsoft, the group "Power Users" has "no default user rights", while the group "Users" has rights to "perform common tasks, such as running applications, using local and network printers".
The solution was to add my user(s) to the group "Users". This immediately solved the issue and allowed cmdkey to work in Powershell Logon Scripts.
I had this same problem with a PowerShell GPO logon script calling cmdkey.exe. The credentials populated into Credential Manager for Users, but Administrators the credentials did not show up. I found out that the credentials are saving in Credential Manager, but for the elevated user. If you run cmdkey /list in an elevated command prompt you will see the credentials there.

Powershell start IE on remote machine with specific URL

Is there a way to start IE on a remote machine pointing it to a specific URL using powershell.
This script will only open on my local machine:
$PC = Read-Host "Name of machine to run cookie creator on"
$URL = "http://www.google.co.uk"
$ie = New-Object -com InternetExplorer.Application
$ie.visible=$true
$ie.navigate($URL)
Any ideas? Thanks
You can't.
When you use PowerShell remoting, it creates a session on the remote computer which cannot be interacted with and has no UI. So while you can start the IE process, the UI will never be visible to any user.