PowerShell script with messagebox don't show on remote computer - powershell

This is my script:
$name = function Get-Name {
$env:computername
}
Get-Name
$time = function Get-SystemUptime {
$operatingSystem = Get-WmiObject Win32_OperatingSystem
"$((Get-Date) - ([Management.ManagementDateTimeConverter]::ToDateTime($operatingSystem.LastBootUpTime)))"
}
Get-SystemUptime
$string = Get-SystemUptime
$separator = "\."
$string.Split($separator, 2)
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
Add-Type -AssemblyName PresentationFramework
Add-Type –AssemblyName System.Windows.Forms
$days = $string.Split(".")[0]
if ([convert]::ToInt32($days, 10) -ge 1) {
$MsgboxTxt = "TXT $($days) TXT"
$MsgboxTitle = '!!! TXT !!!'
[System.Windows.Forms.MessageBox]::Show($MsgboxTxt, $MsgboxTitle, [Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Stop, [System.Windows.Forms.MessageBoxDefaultButton]::Button1, [System.Windows.Forms.MessageBoxOptions]::DefaultDesktopOnly)
}
I start it with this command on remote computer by my company program who runs it with batch (CMD) administration rights:
Powershell.exe -ExecutionPolicy RemoteSigned -File uptime.ps1
When I run in on local computer by copy file and run it from CMD in local priveliges it's OK. Everything working fine.
I think my company program (LOGSystem) runs it on administration user, not logged user.
Is there a option to run it on logged users using CMD command or else?

Related

Run powershell script when lid closed on a laptop

I want to run a powershell script when i close the lid on a laptop with windows 10, if there isn't an external monitor attached to te pc, it goes sleep. The script works well if i lauch it manually, but i cannot find inside task scheduler an activation event like 'closing the lid'.
This is the powershell script:
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
if ( #(Get-CimInstance -Namespace root\wmi -ClassName WmiMonitorBasicDisplayParams | where-object { $_.Active }).Length -eq 1 )
{
#put laptop to sleep if there are no external monitor connected
$PowerState = [System.Windows.Forms.PowerState]::Suspend;
$Force = $true;
$DisableWake = $false;
[System.Windows.Forms.Application]::SetSuspendState($PowerState, $Force, $DisableWake);
}

Set a variable equal to the output of a powershell script

This is a little difficult to explain, but I will do my best. I am writing some code to import AD contacts to users' mailboxes through EWS using Powershell.
I have a Main.ps1 file that calls all the other scripts that do work in the background (for example 1 imports the AD modules) another imports O365 modules.
I have 1 script container that connect to EWS. The code looks like this:
#CONFIGURE ADMIN CREDENTIALS
$userUPN = "User#domain.com"
$AESKeyFilePath = ($pwd.ProviderPath) + "\ConnectToEWS\aeskey.txt"
$SecurePwdFilePath = ($pwd.ProviderPath) + "\ConnectToEWS\password.txt"
$AESKey = Get-Content -Path $AESKeyFilePath -Force
$securePass = Get-Content -Path $SecurePwdFilePath -Force | ConvertTo-SecureString -Key $AESKey
#create a new psCredential object with required username and password
$adminCreds = New-Object System.Management.Automation.PSCredential($userUPN, $securePass)
Try
{
[Reflection.Assembly]::LoadFile("\\MBX-Server\c$\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll") | Out-Null
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1)
$service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials($userUPN,$adminCreds.GetNetworkCredential().Password)
$service.Url = new-object Uri("https://outlook.office365.com/EWS/Exchange.asmx");
return $service
}
Catch
{
Write-Output "Unable to connect to EWS. Make sure the path to the DLL or URL is correct"
}
The output of that code prints out the Service connection, but I want the information for that output stored in a variable such as $service.
Then I would pass that variable to another script that binds to the mailbox I want...
The problem I am having is $service doesn't seem to be storing that information. It only print it out once when I return it from the script above, but it doesn't append that information in the main script. When I print out $service it prints out once, but then it clears itself.
Here is my main script
CLS
#Root Path
$rootPath = $pwd.ProviderPath #$PSScriptRoot #$pwd.ProviderPath
Write-Host "Importing all necessary modules."
#******************************************************************
# PREREQUISITES
#******************************************************************
#Nuget - Needed for O365 Module to work properly
if(!(Get-Module -ListAvailable -Name NuGet))
{
#Install NuGet (Prerequisite) first
Install-PackageProvider -Name NuGet -Scope CurrentUser -Force -Confirm:$False
}
#******************************************************************
#Connect w\ Active Directory Module
& $rootPath\AD-Module\AD-module.ps1
#Load the O365 Module
& $rootPath\O365-Module\O365-module.ps1
#Clear screen after loading all the modules/sessions
CLS
#******************************************************************
# PUT CODE BELOW
#******************************************************************
#GLOBAL VARIABLES
$global:FolderName = $MailboxToConnect = $Service = $NULL
#Connect to EWS
& $rootPath\ConnectToEWS\ConnectToEWS.ps1
#Debug
$Service
#Create the Contacts Folder
& $rootPath\CreateContactsFolder\CreateContactsFolder.ps1
#Debug
$service
$ContactsFolder
#Clean up Sessions after use
if($NULL -ne (Get-PSSession))
{
Remove-PSSession *
}
[GC]::Collect()
The first time I output the $service variable, it prints fine. In the 2nd Debug output it doesn't print out anymore, and I believe that it why the script is failing when I launch "CreateContactsFolder.ps1"
Here is the content of "CreateContactsFolder.ps1"
CLS
Try
{
$service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $MailboxToConnect);
$RootFolder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)
$RootFolder.Load()
#Check to see if they have a contacts folder that we want
$FolderView = new-Object Microsoft.Exchange.WebServices.Data.FolderView(1000)
$ContactsFolderSearch = $RootFolder.FindFolders($FolderView) | Where-Object {$_.DisplayName -eq $FolderName}
if($ContactsFolderSearch)
{
$ContactsFolder = [Microsoft.Exchange.WebServices.Data.ContactsFolder]::Bind($service,$ContactsFolderSearch.Id);
#If folder exists, connect to it. Clear existing Contacts, and reupload new (UPDATED) Contact Info
Write-Output "Folder alreads exists. We will remove all contacts under this folder."
# Attempt to empty the target folder up to 10 times.
$tries = 0
$max_tries = 0
while ($tries -lt 2)
{
try
{
$tries++
$ErrorActionPreference='Stop'
$ContactsFolder.Empty([Microsoft.Exchange.WebServices.Data.DeleteMode]::HardDelete, $true)
$tries++
}
catch
{
$ErrorActionPreference='SilentlyContinue'
$rnd = Get-Random -Minimum 1 -Maximum 10
Start-Sleep -Seconds $rnd
$tries = $tries - 1
$max_tries++
if ($max_tries -gt 100)
{
Write-Output "Error; Cannot empty the target folder; `t$EmailAddress"
}
}
}
}
else
{
#Contact Folder doesn't exist. Let's create it
try
{
Write-Output "Creating new Contacts Folder called $FolderName"
$ContactsFolder = New-Object Microsoft.Exchange.WebServices.Data.ContactsFolder($service);
$ContactsFolder.DisplayName = $FolderName
$ContactsFolder.Save([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot)
}
catch
{
Write-Output "Error; Cannot create the target folder; `t$EmailAddress"
}
}
}
Catch
{
Write-Output "Couldn't connect to the user's mailbox. Make sure the admin account you're using to connect to has App Impersonization permissions"
Write-Output "Check this link for more info: https://help.bittitan.com/hc/en-us/articles/115008098447-The-account-does-not-have-permission-to-impersonate-the-requested-user"
}
return $ContactsFolder
In the Main script, capture the returned variable from the EWS script like
$service = & $rootPath\ConnectToEWS\ConnectToEWS.ps1
Or dot-source that script into the Main script, so the variables from EWS.ps1 are local to the Main script, so you don't need to do return $service in there:
. $rootPath\ConnectToEWS\ConnectToEWS.ps1
and do the same for the CreateContactsFolder.ps1 script
OR
define the important variables in the called scripts with a global scope $global:service and $global:ContactsFolder
See About_Scopes

How to take a remote screenshot with Powershell

I'm trying to figure out how to take remote screenshots over PowerShell from an administrator's account on the AD server to any computer on the network.
So far I've got the following.
$ComputerName = '<THECOMPUTER>'
copy-item "C:\Public\Software\Take-Screenshot.ps1" "\\$ComputerName\C$\"
Invoke-Command -ComputerName $ComputerName -ScriptBlock {
powershell -nop -c "C:\Take-Screenshot.ps1"
}
Take-Screenshot.ps1 is in from here, but I've added the following to the bottom of the script to actually run the function.
Take-ScreenShot -screen -file C:\s.png -imagetype png
After the screenshot is taken, I'll copy it back to the host, but the problem is the picture is completely black.
I'm thinking this might be because the powershell is running the program, but there's not session attached to it, so there really is not screen??
So I got this to work but it is a little involved. Works with multiple monitors.
You will need Screenshot.ps1 on the remote PC, your trigger script and PSExec on local PC (Google).
# This is Screenshot.ps1
# Add types and variables
$File = "C:\Temp\Screenshot1.bmp"
Add-Type -AssemblyName System.Windows.Forms
Add-type -AssemblyName System.Drawing
# Gather Screen resolution information
$Screen = [System.Windows.Forms.SystemInformation]::VirtualScreen
$Width = $Screen.Width
$Height = $Screen.Height
$Left = $Screen.Left
$Top = $Screen.Top
# Set bounds
$bitmap = New-Object System.Drawing.Bitmap $Width, $Height
# Create Object
$graphic = [System.Drawing.Graphics]::FromImage($bitmap)
# Capture
$graphic.CopyFromScreen($Left, $Top, 0, 0, $bitmap.Size)
# Save
$bitmap.Save($File)
And then for the trigger script
#Setup Variables
$ComputerName = "ComputerName"
$PSExec = "C:\temp\tools\psexec.exe"
# Captures session details
$quser = (((query user /server:$ComputerName) -replace '^>', '') -replace '\s{2,}', ',' | ConvertFrom-Csv)
# Takes screenshot of remote PC
&$PSExec -s -i $quser.ID "\\$ComputerName\" PowerShell -WindowStyle Hidden -File "C:\Temp\screenshot.ps1"

Use powershell command in add_click

I do a basic powershell script with a window and a simple button,
On the add_click action i want to execute the "powershell -file $path" command to open another script
in the main the command works, but not when it is in the .add_click({ })
#main
Add-Type -AssemblyName System.Windows.Forms
$form = New-Object Windows.Forms.Form
$btn1 = New-Object Windows.Forms.Button
$btn1.Text = "Button1"
$form.Controls.Add($btn1)
$path = "C:\Users\Administrateur\Desktop\export_vers_test\test_cmd.ps1"
#powershell -file $path #Here it works
$btn1.add_Click({
write-host $path
powershell -file $path #Here it works doesn't works
})
$form.ShowDialog()
Can i have some help please?
You need to pass the string path to your powershell function.
Use paramters for that.
Your function:
function Set-ActionOnClic{
param($path)
write-host $path
}
the call in the click event
$btn1.add_Click({
Set-ActionOnClic -path $path
#Run the script
. $Path
})

Install program remotely using Invoke-Command

The variable at the top of the script defines several commands/variables for New-PSDrive, as well as connection and installation.
After this, a function is created to open a text file and extract information out of it. I know this part works because I use it in 2 other scripts.
Lastly, The script executes the commands in the first variable.
The script will show as running successfully, but checking the remote computer reveals that nothing happened.
Prior to doing any of this activity, the remote computer has a script run against it that:
enables PSRemoting (setting firewall rules and starting WinRM), and
bypasses execution policies.
After those steps, the script below is run to install a piece of software.
$eAudIT2014V2Install = {
$eAudIT2014V2password = ConvertTo-SecureString "PasswordHere" -AsPlainText -Force
$eAudIT2014V2cred = New-Object System.Management.Automation.PSCredential('domain\user', $eAudIT2014V2password)
$eAudIT2014V2drive = New-PSDrive -Name eAudIT2014V2 -PSProvider FileSystem -Root "\\Server\Share" -Credential $eAudIT2014V2cred
$eAudIT2014V2job = Start-Job {"eAudIT2014V2:\Setup.cmd"}
Wait-Job $eAudIT2014V2job
Receive-Job $eAudIT2014V2job
}
Function Get-OpenFile($initialDirectory) {
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") |
Out-Null
$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.InitialDirectory = $initialDirectory
$OpenFileDialog.ShowDialog()
$OpenFileDialog.Filename
$OpenFileDialog.ShowHelp = $true
}
$InputFile = Get-OpenFile
if ($InputFile -eq "Cancel") {
Write-Host "Canceled By User"
exit
} else {
$Computers = #(Get-Content -Path $InputFile)
}
foreach ($computer in $computers) {
Write-Host "Installing eAudIT 2014V2 on Selected Computers"
Invoke-Command $eAudIT2014V2Install
}
I'm noticing that if I tell this script to run something basic like notepad.exe, a dllhost process starts on the machine, but notepad never does. What am I doing wrong?
The answer is pretty simple here. All of your script is for naught if you don't tell the Invoke-Command cmdlet what computer you want to execute the code on. As it is you are simply iterating a loop and invoking that command X number of times on the local machine. You need to change that second to the last line to specify the machine to execute the code on:
Invoke-Command $eAudIT2014V2Install -ComputerName $computer