When I am running commands or installing software remotely using PowerShell - Invoke-Command etc I would like sometimes to be able to show a message on the remote screen so the user knows something is happening, or when work done etc.
I would like to if possible make this message look as professional as possible, e.g. better than just a standard winform message box if it can be done? perhaps more the style of the Windows 10 ones with coloured background and use of image if possible.
Spent a while googling but most seem to relate to using obsolete methods such as net-send or using msg.exe.
Thanks
https://michlstechblog.info/blog/powershell-show-a-messagebox/
So the issue really isnt creating the messagebox itself, its having it show on the users session.
So when you run a command against a system, youre using your creds to run the command therefore it wont show in the users session. You can get around this by running it in the users context using a task scheduler. I have a script that does all this for you but, id hate to recreate the wheel and will have to wait till monday (when im at work) to post it here.
It accepts user input in your sessions that outputs it to a vbs, which then copies it over the message to the users machine, and a task schedule is set to run immediately for the user thats logged in.
edit: The script is this without the task scheduler. I just invoke gwmi win32_computersystem | Select -ExpandProperty username to get the current user logged in and add it to the task.
#Prompt for messge
$strMSG = Read-Host -Prompt "Enter message"
#deleting vbs if it exists
del C:\brief\test.vbs
#creating vbs from scratch so it doesnt override
New-Item C:\brief\test.vbs
#Appending each the values to a seperate line
Add-Content C:\brief\test.vbs 'Set objShell = Wscript.CreateObject("WScript.Shell")'
Add-Content C:\brief\test.vbs "strText = `"$strMSG`""
Add-Content C:\brief\test.vbs 'intButton = objShell.Popup(strText,0,"Computer Support",48)'
#calling on the script
& cscript C:\brief\test.vbs
Found a great solution here which appears on quick testing to work well for displaying a toast notification on a remote machine
https://smsagent.blog/2019/06/11/just-for-fun-send-a-remote-toast-notification/
Related
I have a Powershell script designed to automate the testing of some URLs. The script invokes an Internet Explorer session as such:
$IEProcess = Start-Process -FilePAth 'C:\Program Files (x86)\Internet Explorer\iexplore.exe' -ArgumentList "-private $url"
$Shell = New-Object -ComObject Shell.Application
$IE = $Shell.Windows()
It then proceeds to use the $IE object to navigate to different URLs, perform various checks against the pages HTML document bodies and take screenshots of the resulting web pages. Ultimately, the IE session is ended and the screenshots are distributed via email as attatchments.
The script works perfectly when logged onto the virtual host-machine with a service account, that has the necessary permissions for single-sign-on to the various URLs. However, the requirement is for the script to run remotely as a scheduled task, on a daily basis. There should be no interaction by a user other than opening the resulting email.
I have had a job set up in AutoSys to execute the script remotely, once a day, with highest privileges; but the script fails to complete as expected. Specifically, the .Windows() method fails passing the following error message:
Exception calling "Windows" with "0" argument(s): "The server process could not
be started because the configured identity is incorrect. Check the username an
d password. (Exception from HRESULT: 0x8000401A)"
I have to give the job of scheduling the task in autosys to someone else (for security reasons) but I trust that they have configured the job with the appropriate username/password for the necessary service account.
Some online sources suggest to me that the issue might lie with trying to use _ComObjects remotely, and that instances of Internet Explorer require an interactive user session with a UI - which isn't standard config for an autosys batch job.
I have had my autosys-guy add a flag to the job description which should make the user session "interactive", but the script still doesn't execute correctly.
I'm looking for some general insight on the topic and hopefully a solution to get the job running. If anyone cares to help me out I would greatly appreciate it! :)
I also have a more focussed question:
Even if I managed to get a handle on the IE session, should I expect the screenshots that the script takes to fail since the screen buffer for the VM has no monitor to render to? - The images are bitmap and refer to the IE shell objects "position", "width" and "height" for capture placement/dimensions; which presumably mean nothing without a screen resolution??
Thank you for taking the time to read my issue!
So this may be an odd request and maybe I'm going about this all wrong but I also have a unique situation. I have servers that are sometimes cloned and I need to run a script that I created on the clones servers. Due to the nature of the clones they cannot be connected to a network.
Currently I am manually putting the generic script on each server before cloning and then running the script on the clone server.
What I would like to do is have a script that runs and gathers all the information, say installed programs as an example, and generate a custom version of my current script on the servers before they are cloned.
I have both the powershell script that gets the server information and the generic one that makes the changes to the clone but I have not found a way to merge the two or any documentation so I don't know if i am hitting a limitation with this one.
Edit for more explanation and examples. I'm doing this from my phone atm so I dont have an example I can post.
Current I have a script that has a set number of applications to uninstall, registry keys to remove, services to stop ect. In another application I have a list of all the software that we have for each server and I can pull that data for each server. What I need to do is pull the data for each server, and have a script placed on each server that will uninstall just the programs for that server.
Currently the script has to run through every potential software and try to uninstall it and then check the other application to see if there are any additional programs that need to be uninstalled.
Hope this extra info helps.
Thanks.
Stop thinking of it as code.
Use script 1 to export blocks of text into a new file. for example, you might have a configuration that says all Dell servers must have this line of code run:
Set-DELL -attribute1 unmanaged
where on HP, the script would have been
Set-HP -attribute1 unmanaged
on web servers, you want:
set-web -active yes
where if not a web server, you want nothing.. so, your parent script code would look like:
$Dell = "Set-DELL -attribute1 unmanaged"
$HP = "Set-HP -attribute1 unmanaged"
$web = "set-web -active yes"
if (Get-servermake -eq "Dell")
{
$dell | out-file Child.ps1 -append
}
if (Get-servermake -eq "HP")
{
$HP | out-file Child.ps1 -append
}
if (Get-webserver -eq $true)
{
$web | out-file Child.ps1 -append
}
The result is a customized script for the specific server, child.ps1.
Now, you can take this and run with it. You could say add functionality to the child script like "Is it an AD controller", etc.
However, you might be better off having all of this in a single script, and just block off sections that don't apply in an if statement for example.
I'm still not totally sure I understand what your asking. If I've missed the mark, tell me how, and I'll tell you how to tweak this better. (And hopefully obvious is that the Get-whatever is sample code. I don't expect that to be what your using to determine a computer make/model/etc)
I have been trying to get this to work via a game control panel TCAdmin.
$ModPg1 = Invoke-WebRequest "http://steamcommunity.com/sharedfiles/filedetails/?id=731604991"
$ModVer1 = ($ModPg1.ParsedHtml.getElementsByTagName('div') | Where{ $_.className -eq 'detailsStatRight' } ).innerText | Select -Last 1
If I run this cmdlet via a program like TCAdmin (or task scheduler), I get the following error....
Invoke-WebRequest : The response content cannot be parsed because the Internet Explorer engine is not available, or Internet Explorer's first-launch configuration is not complete. Specify the UseBasicParsing parameter and try again.
Explorer is installed, and set up. The script works just fine if I run it manually.
My guess is there is a way to get TCAdmin to run the scripts the same way I would as a windows User.
Cant find a way nearly as simple to scrape the info 'm looking for.
As for this...
get TCAdmin to run the scripts the same way I would as a windows User.
For any app to run as a user, that users profile must be used on the host where the code is to be run. You cannot natively run PoSH on a host as another user context. This is not a PoSH issue, it is a Windows User Principal security boundary. There are tools that let you do this. For example SysInternal PSExec and AutoIT. Yet as stated that error is pretty specific. The user profile for Internet Explorer has not been created and that only happens when you use IE at least once.
So, as Adam points, out, use the setting the error message states to use or use your code to start IE at least once.
$SomeUrl = 'https://stackoverflow.com'
$ie = New-Object -com internetexplorer.application
$ie.visible = $true
$ie.navigate($SomeUrl)
while ($ie.Busy -eq $true) { Start-Sleep -Seconds 1 } # Wait for IE to settle.
Again, if trying to run this in the context of another user, the two above tools will get you there, but you still have to fire up IE to have a profile for it.
I created PowerShell script wich install an application on computer (windows 7).
This script is in GPO and deployed with GPO at logon users. This worked fine, but I want that at the end of installation, my powershell script send at the current logged user on computer a message like "Reboot your computer please".
I tested many things but I don'tview popup, maybe because my script are execute with admin rights (not with user rights).
Test :
#$wshell = New-Object -ComObject Wscript.Shell
#$wshell.Popup("Operation Completed",0,"Done",0x1)
[Windows.Forms.MessageBox]::Show(“My message”, , [Windows.Forms.MessageBoxButtons]::OK, [Windows.Forms.MessageBoxIcon]::Information)
Your script may be popping up the message but then closing the PowerShell console immediately after, removing the popup. Try waiting on the result of the popup before closing the PowerShell instance:
$wshell = New-Object -ComObject Wscript.Shell
$result = $wshell.Popup("Operation Completed",0,"Done",0x1)
You need to load the assembly providing the MessageBox class first, and you cannot omit the message box title if you want to specify buttons and/or icons.
Add-Type -Assembly 'System.Windows.Forms'
[Windows.Forms.MessageBox]::Show(“My message”, "", [Windows.Forms.MessageBoxButtons]::OK, [Windows.Forms.MessageBoxIcon]::Information)
# ^^
You can use an empty string or $null here, but simply not providing a value (like you could do in VBScript) is not allowed.
As a side-note, I'd recommend avoiding typographic quotes in your code. Although PowerShell will tolerate them most of the time, they might cause issues sometimes. Always use straight quotes to be on the safe side.
Edit: Since you're running the script via a machine policy it cannot display message boxes to the logged-in user, because it's running in a different user context. All you can do is have a user logon script check whether the software is installed, and then display a message to the user. This works, because a user logon script running in the user's context.
I'm using IIS 6.0 and looking for a way to stop/start the app pool. I know there is a stop-appPool for powershell in 7.0 but using 6.0. :-( So does anyone have a powershell script or another command line exe that will stop/start the app pool?
Thanks.
Ok here it is, I just add a switch to stop the app pool else it starts since no harm in starting an app pool that is already started:
param([string]$appPoolName, [switch]$stop)
$appPool = get-wmiobject -namespace "root\MicrosoftIISv2" -class "IIsApplicationPool" | where-object {$_.Name -eq "W3SVC/AppPools/$appPoolName"}
if($appPool)
{
if($stop)
{
$appPool.Stop()
}
else
{
$appPool.Start()
}
}
If anybody is looking for a purely command-line tool that does not require Powershell, I have created such a thing based on the information contained in these other answers. Since the original question is specifically looking for possible command-line alternatives, I thought I would share it here.
Usage is quite simple:
IIS6AppPool Start DefaultAppPool
IIS6AppPool Stop AppPool #1
IIS6AppPool Recycle Some other app pool
Source and binaries are available on bitbucket. May this save somebody else a few minutes of head scratching.
You might be interested in this Powershell library I started maintaining:
psDeploy : http://rprieto.github.com/psDeploy/
Among other things it has lots of cmdlets for IIS6 automation, for example Start-IIS6AppPool, New-IIS6Website...
I hope it helps!
If on Windows Server 2003 it is simpler to use the supplied script iisapp.vbs
CScript.exe C:\WINDOWS\system32\iisapp.vbs /?
CScript.exe C:\WINDOWS\system32\iisapp.vbs /a MyApp /r
Or depending on your setup (default to Cscript not WScript), simply
iisapp /a MyApp /r
And of course it is different in IIS7
If you wish to do this remotely, and / or on a machine without powershell you can modify the script posted here.
It uses WMI to access and recycle the app pool, from VBScript. It's a trivial change to make it stop / start pools instead of recycling them, you just need to call .Stop or .Start on the app pool in question.
The meat of the script is paraphrased below:
strServer = "LocalHost" 'Server name goes here
strAppPoolName = "MyAppPool" 'App pool name goes here
'Connect to the specified server using WMI
set Locator = CreateObject("WbemScripting.SWbemLocator")
Locator.Security_.AuthenticationLevel = 6
set Service = locator.connectserver(strServer,"root/MicrosoftIISv2")
'Get a collection of WMI apppools
set APCollection = Service.InstancesOf("IISApplicationPool")
For each APInstance in APCollection
If UCase(ApInstance.Name) = UCase("W3SVC/AppPools/" & strAppPoolName) Then
WScript.Echo "Recycling " & strServer & "/" & APInstance.Name
' You can do any of these things depending you what you want to do.
APInstance.Recycle
APInstance.Stop
APInstance.Start
End If
Next
If you have some kind of command line / batch toolchain which you want to integrate this into, you can execute a VBScript file in command line mode by calling:
CScript.exe \NoLogo MyScriptFile.vbs
The \NoLogo switch removes the VBScript interpreter startup messages and running it with CScript.exe means that calls to WScript.Echo go to the command line rather than a popup window.
You could create a function to stop or start the application pool remotely as below:
function StopOrStartAppPool($RemoteServerName, $AppPoolName, $commandWebPool)
{
if ($commandWebPool -eq "Stop")
{
$wmiprocess = [wmiclass]"\\$RemoteServerName\root\cimv2:win32_process"
$wmiprocess.create("cscript.exe C:\Inetpub\AdminScripts\adsutil.vbs STOP_SERVER W3SVC/AppPools/$AppPoolName -s:$RemoteServerName")
}
else
{
$wmiprocess = [wmiclass] "\\$RemoteServerName\root\cimv2:win32_process"
$wmiprocess.create("cscript.exe C:\Inetpub\AdminScripts\adsutil.vbs START_SERVER W3SVC/AppPools/$AppPoolName -s:$RemoteServerName")
}
}