When I have created scripts, that are to used in Production, I put in code that will write events to a specific Event Log so, in the event of a failure, I can use my events as a starting point for resolving the issue.
Writing your own events is relatively easy. As an example, let's say I have a process that should be running 24x7. The first thing to do is to look for the process:
$process = get-process MyProcess -ErrorAction SilentlyContinue
The '-ErrorAction SilentlyContinue' is needed because the get-process code would fail if the process isn't running.
The next step is to make the appropriate event log available to add events:
New-EventLog -LogName Application -Source "My Process Code"
The 'Log-Name' parameter needs to have the correct event log. In this example, we want to add the events to the Application log
The '-Source' parameter is used to give name/label to the event.
At this point, we have the following code for the script:
$process = get-process MyProcess -ErrorAction SilentlyContinue
New-EventLog - LogName Application -Source "My Process Code"
Now that we have information about the process, and have the event log ready, we need to evaluate the $process variable. First, let's check to see if the $process was running:
if($process) {
Write-EventLog -LogName Application -Source "My Process Code" -EntryType information -EventID 3000 -Message "My Process is running"
}
This line of code states that IF $process is true (because there is information in the variable), then write a event into the Application log, the source is My Process Code, the entry type is Information, give the event ID as 3000, and the message is the process is running.
Now, what if $process is empty, meaning the process was not running? We add and Else statement to handle this situation:
Else {
Write-EventLog -LogName Application -Source "My Process Code" -EntryType Error -EventID 3001 Message "My Process is not running"
}
As you can see, only change we made were the entry type, the event ID, and the message.
In my scripts, I will add a line, in the Else code, that restarts the process. So, it would look like this:
Else {
Write-EventLog -LogName Application -Source "My Process Code" -EntryType Error -EventID 3001 Message "My Process is not running"
Invoke-expression "C:\Applications\MyProcess.exe"
}
Here is what the complete script will look like:
$process = get-process MyProcess -ErrorAction SilentlyContinue
New-EventLog - LogName Application -Source "My Process Code"
if($process) {
Write-EventLog -LogName Application -Source "My Process Code" -EntryType information -EventID 3000 -Message "My Process is running"
}
Else {
Write-EventLog -LogName Application -Source "My Process Code" -EntryType Error -EventID 3001 Message "My Process is not running"
Invoke-expression "C:\Applications\MyProcess.exe"
}
I hope you find this article helpful. Please feel free to contact me if you have any questions.
Mike
Sunday, May 26, 2019
Wednesday, May 22, 2019
I'm coming back
Greetings everyone!
After a lengthy hiatus, I will be coming back with some cool scripts I have been using over the last 14 months.
So, stay tuned!
Mike
After a lengthy hiatus, I will be coming back with some cool scripts I have been using over the last 14 months.
So, stay tuned!
Mike
Sunday, May 13, 2018
BREAKING NEWS: Powershell isn't always the answer
Greetings!
It is hard for me to say that Powershell isn't the end all, be all for automation. But, at times, the simplest solution is the best. In this case it was stopping and starting custom applications.
We have a server that needs to run two custom applications. We will call these App1 and App2. These applications have to be running in the foreground. The first script stopped the applications by using a .bat file that contained the following code:
TASKKILL /IM App1.exe /F
TASKKILL /IM App2.exe /F
The script to start the applications contained the following code:
START C:\app1.exe
START C:\app2.exe
We were using Task Scheduler to run the scripts every morning at 4:00am. When the tasks ran, the apps would stop but the apps wouldn't start in the foreground.
At first we thought we could create a Powershell script to get the applications to run in the foreground. Unfortunately, we had the same problem when we created a scheduled task to run the Powershell script.
As we were trying to figure out why this was happening, our boss, Amos, came into the room and asked if he could take a look at the scheduled task. After a minute he said, "I found the problem. You have to use Run only when user is logged on. This setting will start the applications in the foreground. Using Run whether user is logged on or not will force the applications to start in the background." We made the changes and the applications started correctly.
So, we learned that it is necessary to know how to use the tools that will run your scripts.
I hope you find this useful.
Mike
It is hard for me to say that Powershell isn't the end all, be all for automation. But, at times, the simplest solution is the best. In this case it was stopping and starting custom applications.
We have a server that needs to run two custom applications. We will call these App1 and App2. These applications have to be running in the foreground. The first script stopped the applications by using a .bat file that contained the following code:
TASKKILL /IM App1.exe /F
TASKKILL /IM App2.exe /F
The script to start the applications contained the following code:
START C:\app1.exe
START C:\app2.exe
We were using Task Scheduler to run the scripts every morning at 4:00am. When the tasks ran, the apps would stop but the apps wouldn't start in the foreground.
At first we thought we could create a Powershell script to get the applications to run in the foreground. Unfortunately, we had the same problem when we created a scheduled task to run the Powershell script.
As we were trying to figure out why this was happening, our boss, Amos, came into the room and asked if he could take a look at the scheduled task. After a minute he said, "I found the problem. You have to use Run only when user is logged on. This setting will start the applications in the foreground. Using Run whether user is logged on or not will force the applications to start in the background." We made the changes and the applications started correctly.
So, we learned that it is necessary to know how to use the tools that will run your scripts.
I hope you find this useful.
Mike
Monday, April 30, 2018
Web Site Restart
Greetings,
We have had occasion to find a way to restart a web site when we get a notification that the site is unavailable. The restart process includes restarting the associated application pool (app pool) and the site itself. In PowerShell, this task is simple to accomplish. The code is as follows:
$wstate = Get-Website -Name 'Default Web Site'
$pstate = Get-IISAppPool -Name DefaultAppPool
if ($wstate.state -ne "Started") {
Restart-WebAppPool -Name DefaultAppPool
Start-Website -Name 'Default Web Site'
}
We will use the Default Web Site in this example. The first line ($wstate = Get-Website -Name 'Default Web Site'), gets all the information regarding the default web site, including its state (started, stopped). The second line ($pstate = Get-IISAppPool -Name DefaultAppPool ) gets the information regarding the app pool for the default web site.
Within the IF statement, if the state of the website ($wstate) is not 'Started' then the app pool is restarted (Restart-WebAppPool) and the web site is started (Start-Website).
To verify the site has started you can add the following commands to start a browser and browse to the site:
$url = 'http://<your web site>'
$ie.Visible = $true
$ie = new-object -ComObject internetexplorer.application
$ie.Navigate($url)
I hope this information is helpful.
Mike
We have had occasion to find a way to restart a web site when we get a notification that the site is unavailable. The restart process includes restarting the associated application pool (app pool) and the site itself. In PowerShell, this task is simple to accomplish. The code is as follows:
$wstate = Get-Website -Name 'Default Web Site'
$pstate = Get-IISAppPool -Name DefaultAppPool
if ($wstate.state -ne "Started") {
Restart-WebAppPool -Name DefaultAppPool
Start-Website -Name 'Default Web Site'
}
We will use the Default Web Site in this example. The first line ($wstate = Get-Website -Name 'Default Web Site'), gets all the information regarding the default web site, including its state (started, stopped). The second line ($pstate = Get-IISAppPool -Name DefaultAppPool ) gets the information regarding the app pool for the default web site.
Within the IF statement, if the state of the website ($wstate) is not 'Started' then the app pool is restarted (Restart-WebAppPool) and the web site is started (Start-Website).
To verify the site has started you can add the following commands to start a browser and browse to the site:
$url = 'http://<your web site>'
$ie.Visible = $true
$ie = new-object -ComObject internetexplorer.application
$ie.Navigate($url)
I hope this information is helpful.
Mike
Monday, April 23, 2018
When did these Pings run?
Greetings.
Took a little break from the blog. I'm back and I have a script I created for my colleague, Tom.
Tom called me and wanted to know if there was a way to get time stamps when pinging a server. To clarify, show a time stamp for each return value from the ping. In addition, the script should run like the Ping -t command and dump the output into a text file.
I researched how to ping within Powershell and found that the Test-Connection cmdlet will do what Tom has requested. I started by creating a variable that will be used by the While loop
$i = 1
Then, we create the While loop
While ($i = 1){
}
This will run the commands within the loop until $i is something other than 1.
Now, we create the body of the script. We will run the script against Google (www.google.com)
test-connection www.google.com | select @{N='Time';E={[dateTime}::Now}},@{N='Destination';E={$_.address}},replysize,@{N='Time(ms)';E={$_.Responsetime}} | export-csv -append c:\ping.txt
In the 'select' statement:
@{N='Time';E={[dateTime]::Now}}....This will create a column called 'Time' and this column will hold information from the [dateTime]::Now expression
@{N='Destination';E={$_.address}}...this will create a column called 'Destination' containing the information in the $_.address field
replysize...this is the size of the reply pack in Bytes
@{N='Time(ms)';E={$_.ResponseTime}}...this will create a column called 'Time(ms)' containing the information in the $_.ResponseTime field
The last part of the statement will send the output to a file called Ping.txt in a comma-separated value (CSV) format
In the end, the script will look like this:
$i = 1
While ($i = 1) {
test-connection www.google.com | select @{N='Time';E={[dateTime]::Now}},@{N='Destination';E={$_.address}},replysize,@{N='Time(ms)'; E={$_.ResponseTime}} | export-csv -append c:\ping.txt
}
Some of you may be saying, "There isn't any code that changes $i to something other than 1." And you would be correct. This script will run until you manually stop the script, in most cases by using CTRL-C.
The output of the script will look like this:
Mike
Took a little break from the blog. I'm back and I have a script I created for my colleague, Tom.
Tom called me and wanted to know if there was a way to get time stamps when pinging a server. To clarify, show a time stamp for each return value from the ping. In addition, the script should run like the Ping -t command and dump the output into a text file.
I researched how to ping within Powershell and found that the Test-Connection cmdlet will do what Tom has requested. I started by creating a variable that will be used by the While loop
$i = 1
Then, we create the While loop
While ($i = 1){
}
This will run the commands within the loop until $i is something other than 1.
Now, we create the body of the script. We will run the script against Google (www.google.com)
test-connection www.google.com | select @{N='Time';E={[dateTime}::Now}},@{N='Destination';E={$_.address}},replysize,@{N='Time(ms)';E={$_.Responsetime}} | export-csv -append c:\ping.txt
In the 'select' statement:
@{N='Time';E={[dateTime]::Now}}....This will create a column called 'Time' and this column will hold information from the [dateTime]::Now expression
@{N='Destination';E={$_.address}}...this will create a column called 'Destination' containing the information in the $_.address field
replysize...this is the size of the reply pack in Bytes
@{N='Time(ms)';E={$_.ResponseTime}}...this will create a column called 'Time(ms)' containing the information in the $_.ResponseTime field
The last part of the statement will send the output to a file called Ping.txt in a comma-separated value (CSV) format
In the end, the script will look like this:
$i = 1
While ($i = 1) {
test-connection www.google.com | select @{N='Time';E={[dateTime]::Now}},@{N='Destination';E={$_.address}},replysize,@{N='Time(ms)'; E={$_.ResponseTime}} | export-csv -append c:\ping.txt
}
Some of you may be saying, "There isn't any code that changes $i to something other than 1." And you would be correct. This script will run until you manually stop the script, in most cases by using CTRL-C.
The output of the script will look like this:
I hope you find this script helpful. Be sure to comment if you have any questions.Mike
Monday, April 9, 2018
Remoting into Workgroup PCs and a Book Recommendation
Greetings!
While trying to connect to a workstation on our network I discovered the workstation wasn't on our AD domain but was configured for WORKGROUP. That got me thinking, "Can I access WORKGROUP machines via Powershell?". And, by golly, you can. Here's how:
Prerequisite work (this needs to be done on each PC you want to access):
Make sure the workstations are within the same IP and subnet mask range
Open your firewall settings
On the left panel, select "Allow an app or feature through Firewall"
Click on "Change Settings". This will give you access to the apps and features in the list.
Scroll down and select Windows Management Instrumentation (WMI).
Click on the Private box
Scroll down and select Windows Remote Management
Click on the Private box
Click on OK
Close the Firewall window
Configuring Powershell:
Open Powershell with elevated privileges
At the prompt, type:
new-itemproperty -path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System -name LocalAccountTokenFilterPolicy -propertytype DWord -value 1
NOTE: the LocalAccountTokenFilterPolicy setting sets how admin credentials are applied to a
remote computer. A value of 1 is what is used to build the evaluated token
At this point you should be able to create a PSSession to your computer by typing:
enter-pssession localhost
You should see a prompt similar to [localhost]: PS C:\Users.
Type exit-pssession to exit out of the session
If all of the above tasks work on both computers, you should be able to create a session from one computer to another. For example, I have two test workstations, 192.168.100.5 and 192.168.100.6. In order for me to create a session from 100.5 to 100.6, I will do the following:
On 100.5
enter-pssession -computername 192.168.100.6
The prompt will look list [192.168.100.6]: PS C:\users
From here I can start and stop services/processes. I can create files and directories. I will be looking for a way to copy files from a session to the host.
Again, to disconnect the session, type exit-possession
I know this seems like a lot of steps just to allow PSRemoting to WORKGROUP computers. But I know there are still some environments where they have non-domain computers. Why should they be deprived of experiencing Powershell's greatness?
Now, my book recommendation.
I don't do book reviews as well as I should. But, Don Jones' new book, "Be The Master", is worth reading. The main theme of the book is that we all have something to share/teach others. Mr. Jones uses the analogy of the master and apprentice. The master would share all of their knowledge with the apprentice, sometimes at the cost to the apprentice. This allows for a craft/talent to move on (and sometimes is improved upon) to future generations. What I got out of this book is that there are people out there who want to know things that I know. That is why I post stuff to this blog. I love Powershell and I want to share some of the things I have found.
It's a quick ready (about 105 pages) and is available via Amazon at $8.
Well that's what I have for this week. I hope you found both items helpful.
Mike
While trying to connect to a workstation on our network I discovered the workstation wasn't on our AD domain but was configured for WORKGROUP. That got me thinking, "Can I access WORKGROUP machines via Powershell?". And, by golly, you can. Here's how:
Prerequisite work (this needs to be done on each PC you want to access):
Make sure the workstations are within the same IP and subnet mask range
Open your firewall settings
On the left panel, select "Allow an app or feature through Firewall"
Click on "Change Settings". This will give you access to the apps and features in the list.
Scroll down and select Windows Management Instrumentation (WMI).
Click on the Private box
Scroll down and select Windows Remote Management
Click on the Private box
Click on OK
Close the Firewall window
Configuring Powershell:
Open Powershell with elevated privileges
At the prompt, type:
new-itemproperty -path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System -name LocalAccountTokenFilterPolicy -propertytype DWord -value 1
NOTE: the LocalAccountTokenFilterPolicy setting sets how admin credentials are applied to a
remote computer. A value of 1 is what is used to build the evaluated token
At this point you should be able to create a PSSession to your computer by typing:
enter-pssession localhost
You should see a prompt similar to [localhost]: PS C:\Users.
Type exit-pssession to exit out of the session
If all of the above tasks work on both computers, you should be able to create a session from one computer to another. For example, I have two test workstations, 192.168.100.5 and 192.168.100.6. In order for me to create a session from 100.5 to 100.6, I will do the following:
On 100.5
enter-pssession -computername 192.168.100.6
The prompt will look list [192.168.100.6]: PS C:\users
From here I can start and stop services/processes. I can create files and directories. I will be looking for a way to copy files from a session to the host.
Again, to disconnect the session, type exit-possession
I know this seems like a lot of steps just to allow PSRemoting to WORKGROUP computers. But I know there are still some environments where they have non-domain computers. Why should they be deprived of experiencing Powershell's greatness?
Now, my book recommendation.
I don't do book reviews as well as I should. But, Don Jones' new book, "Be The Master", is worth reading. The main theme of the book is that we all have something to share/teach others. Mr. Jones uses the analogy of the master and apprentice. The master would share all of their knowledge with the apprentice, sometimes at the cost to the apprentice. This allows for a craft/talent to move on (and sometimes is improved upon) to future generations. What I got out of this book is that there are people out there who want to know things that I know. That is why I post stuff to this blog. I love Powershell and I want to share some of the things I have found.
It's a quick ready (about 105 pages) and is available via Amazon at $8.
Well that's what I have for this week. I hope you found both items helpful.
Mike
Monday, April 2, 2018
My Process Stopped Processing
Greetings,
Last week I was tasked to create a Powershell script that detects the status of a process running on a Windows 10 computer. If the process wasn't running, the script had to start the process. If the process is in a 'suspended' state, the script had to stop and restart the process. If the process was running, the script display a message.
Detecting the status of the process is relatively simple to do. The first thing you want to do is store the process information in a variable. We will call the variable $process:
$process = get-process myprocess -ErrorAction SilentlyContinue
It is necessary to add the -ErrorAction SilentlyContinue in order to get an empty variable if the process is not running.
Once we have the status of the process, you will have to check if the process is running. To do that we will using an IF statement:
if ($process)
{
}
else
{
invoke-expression "c:\processes\myprocess.exe"
}
If there is something in the $process variable, then we will check the status of the running process. If the variable is empty, then we will start the process using invoke-expression (I will explain this later in the article.
So, if $process is not empty, the next step is to determine if the process is responding. One of the attributes of $process is .Responding. Within the brackets under the IF statement, use the following commands:
{
if ($process.Responding)
{
Write-Host "Process is running"
}
Else
{
Stop-Process -name myprocess -Force
invoke-expression "c:\processes\myprocess.exe"
}
}
This code checks the status of $process.Responding. It will either be True or False. If the process is responding, then a message is returned. If the process is not responding, the process is stopped by force, and the process is restarted.
The reason for using invoke-expression is because my process has a user interface that must be visible when it is running. I couldn't use start-process because the interface would not appear.
The entire script will like as follows:
$process = get-process myprocess -ErrorAction SilentlyContinue
if ($process)
{
if ($process.Responding)
{
Write-Host "Process is running"
}
else
{
Stop-Process -name myprocess -Force
invoke-expression "c:\processes\myprocess.exe"
}
}
else
{
invoke-expression "c:\processes\myprocess.exe"
}
I hope you find this script helpful. Be sure to add a comment if you have any questions, comments, or corrections.
Last week I was tasked to create a Powershell script that detects the status of a process running on a Windows 10 computer. If the process wasn't running, the script had to start the process. If the process is in a 'suspended' state, the script had to stop and restart the process. If the process was running, the script display a message.
Detecting the status of the process is relatively simple to do. The first thing you want to do is store the process information in a variable. We will call the variable $process:
$process = get-process myprocess -ErrorAction SilentlyContinue
It is necessary to add the -ErrorAction SilentlyContinue in order to get an empty variable if the process is not running.
Once we have the status of the process, you will have to check if the process is running. To do that we will using an IF statement:
if ($process)
{
}
else
{
invoke-expression "c:\processes\myprocess.exe"
}
If there is something in the $process variable, then we will check the status of the running process. If the variable is empty, then we will start the process using invoke-expression (I will explain this later in the article.
So, if $process is not empty, the next step is to determine if the process is responding. One of the attributes of $process is .Responding. Within the brackets under the IF statement, use the following commands:
{
if ($process.Responding)
{
Write-Host "Process is running"
}
Else
{
Stop-Process -name myprocess -Force
invoke-expression "c:\processes\myprocess.exe"
}
}
This code checks the status of $process.Responding. It will either be True or False. If the process is responding, then a message is returned. If the process is not responding, the process is stopped by force, and the process is restarted.
The reason for using invoke-expression is because my process has a user interface that must be visible when it is running. I couldn't use start-process because the interface would not appear.
The entire script will like as follows:
$process = get-process myprocess -ErrorAction SilentlyContinue
if ($process)
{
if ($process.Responding)
{
Write-Host "Process is running"
}
else
{
Stop-Process -name myprocess -Force
invoke-expression "c:\processes\myprocess.exe"
}
}
else
{
invoke-expression "c:\processes\myprocess.exe"
}
I hope you find this script helpful. Be sure to add a comment if you have any questions, comments, or corrections.
Subscribe to:
Posts (Atom)
