Friday, June 14, 2019

Web-request all TLS modes

I had fits and starts connecting to servers that had the TLS hardening put on them for web requests.
And a simple setting allowed you to connect to tls1.2 configured web servers.

However, since I was writing a script that could talk to any mode TLS server Like a normal web browser,  I experiment with my limited understanding of .NET request and came up with a short but sweet way to set it.

The I painfully discovered that if you set this more than 2 times, then webrequests would break.
So I added a check to see if it was set, so if this gets in a loop the access doesn't break.


#enable TLS*
if ([Net.ServicePointManager]::SecurityProtocol -ne
    ([Net.SecurityProtocolType].GetEnumNames() |
        ? { $_ -like "Tls*" }))
{
    [Net.ServicePointManager]::SecurityProtocol =
    ([Net.SecurityProtocolType].GetEnumNames() |
        ? { $_ -like "Tls*" }) }
br /> You can set a servers TLS and Crypto setting with:
  http://www.hass.de/content/setup-your-iis-ssl-perfect-forward-secrecy-and-tls-12
  By Alexander Hass
        at your own risk.

I modified his script to not disable any the TLS modes so This could be applied without risk to servers to fix access problems without creating a new problem for apps / scripts that can't ope with TLS ver 1&2
(Which is not to say some other archaic system might have a sezure with changing the criypto settings.

Friday, May 10, 2019

Start-Azure

This is a script to take control of the browser in logging into Microsoft Azure Portal.

I had the recurring irritant, that when I wanted to access my Azure Dashboard,   I had to go through 2 logins, and that is because I was using Chrome browser,  as it worked best in my environment...
and a proxy server login... it took a few steps and because of proxy server required yet another login.
Something not required on IE/Edge"

I needed a way to send keystrokes to the open window and control it that way.
So, I got out some Whip It up a tude,  and started playing in the shell, and searching with google.
(Google knows everything, ya just got to know how to ask.)
A Blog article by Massimo Santin, I found this on his blog.
a-simple-powershell-script-to-send-keys-to-an-application-windows/

Send-Keys.ps1
<#
.SYNOPSIS
Send a sequence of keys to an application window

.DESCRIPTION
This Send-Keys script send a sequence of keys to an application window.
To have more information about the key representation look at http://msdn.microsoft.com/en-us/library/System.Windows.Forms.SendKeys(v=vs.100).aspx
(C)2013 Massimo A. Santin - Use it at your own risk.

.Source 
https://invista.wordpress.com/2013/08/16/a-simple-powershell-script-to-send-keys-to-an-application-windows/

.PARAMETER ApplicationTitle
The title of the application window

.PARAMETER Keys
The sequence of keys to send

.PARAMETER WaitTime
An optional number of seconds to wait after the sending of the keys

.EXAMPLE
Send-Keys "foobar - Notepad" "Hello world"

Send the sequence of keys "Hello world" to the application titled "foobar - Notepad".

.EXAMPLE
Send-Keys "foobar - Notepad" "Hello world" -WaitTime 5

Send the sequence of keys "Hello world" to the application titled "foobar - Notepad" 
and wait 5 seconds.

.EXAMPLE 
    New-Item foobar.txt -ItemType File; notepad foobar.txt ; Send-Keys "foobar - Notepad" "Hello world{ENTER}Ciao mondo{ENTER}" -WaitTime 1; Send-Keys "foobar - Notepad" "^s"

This command sequence creates a new text file called foobar.txt, opens the file using a notepad,
writes some text and saves the file using notepad.

.LINK
http://msdn.microsoft.com/en-us/library/System.Windows.Forms.SendKeys(v=vs.100).aspx
#>
Function Send-Keys {
param (
    [Parameter(Mandatory=$True,Position=1)]
    [string]
    $ApplicationTitle,

    [Parameter(Mandatory=$True,Position=2)]
    [string]
    $Keys,

    [Parameter(Mandatory=$false)]
    [int] $WaitTime
    )

# load assembly cotaining class System.Windows.Forms.SendKeys
[void] [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
#Add-Type -AssemblyName System.Windows.Forms

# add a C# class to access the WIN32 API SetForegroundWindow
Add-Type @"
    using System;
    using System.Runtime.InteropServices;
    public class StartActivateProgramClass {
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetForegroundWindow(IntPtr hWnd);
    }
"@

# get the applications with the specified title
$p = Get-Process | Where-Object { $_.MainWindowTitle -eq $ApplicationTitle }
if ($p) 
{
    # get the window handle of the first application
    $h = $p[0].MainWindowHandle
    # set the application to foreground
    [void] [StartActivateProgramClass]::SetForegroundWindow($h)

    # send the keys sequence
    # more info on MSDN at http://msdn.microsoft.com/en-us/library/System.Windows.Forms.SendKeys(v=vs.100).aspx
    [System.Windows.Forms.SendKeys]::SendWait($Keys)
    if ($WaitTime) 
    {
        Start-Sleep -Seconds $WaitTime
    }
}
}


So I went about utilizing this function to do what I needed, I compiled the information about the windows that needed to be open and what needed to be entered into the windows. and created this script.

start-azure.ps1
<#  
    .NOTES
    ===========================================================================
     Created on:    4/10/2019 6:53 PM
     Created by:    Richard Stoddart
     Organization:  Fabricam.com
     Filename:   start-azure.ps1    
    ===========================================================================
    .DESCRIPTION
        Open Azure session on workstation. 
#>

#Setup
#load function Send-Keys
. "$PSScriptRoot\Send-Keys.ps1"

$EmailFile = "$PSScriptRoot\Email.txt"
$CipherFile = "$PSScriptRoot\Cipher.txt"


#deal with email setting
# delete $EmailFile to restart this query. 

IF (!(Test-Path $EmailFile))
{
    read-host -Prompt "EMAIL File not found! Please Enter EMAIL:" |
    Out-File $EmailFile
}

$Email = Get-Content $EmailFile

#Deal with password cipher

# delete $cipherfile to restart this query. 
IF (!(Test-Path $CipherFile))
{
    read-host -Prompt "Password File not found! Please Enter new Password:" -AsSecureString |
    ConvertFrom-SecureString |
    Out-File $CipherFile
}

# https:portal.azure.com
& "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"  "https://portal.azure.com"
#Waiting for startup. 
$Loop = 100
While ($Loop -gt 1)
{
    If (((Get-Process | ? { $_.ProcessName -eq "chrome" } | 
? { $_.mainwindowtitle -like "Sign in*" }).mainwindowtitle)) { $loop = 0 }
    else { $loop-- }
    if ($loop -eq 1) { Return "timeout opening azure site" }
    Write-Host "." -NoNewline
    Start-Sleep -Seconds 1
}
"`nAzure login open, Proceed"
#enter login info
Send-Keys -ApplicationTitle "Sign in to Microsoft Azure - Google Chrome" -Keys "$email`r"
Start-Sleep -Seconds 2
Send-Keys -ApplicationTitle "Sign in to Microsoft Azure - Google Chrome" -Keys "`r"


#Proxy Server login section

#Waiting for proxy. 
$Loop = 100
While ($Loop -gt 1)
{
    If (
      ((Get-Process | ? { $_.ProcessName -eq "chrome" } |
      ? { $_.mainwindowtitle -like "https://gfs.private.fabricam.com*" }).mainwindowtitle)
     ) 
     { $loop = 0 }
    else { $loop-- }
    if ($loop -eq 1) { Return "timeout logging into proxy" }
    Write-Host "." -NoNewline
    Start-Sleep -Seconds 1
}

$GFSTitle = (Get-Process | ? { $_.ProcessName -eq "chrome" } |
    ? { $_.mainwindowtitle -like "https://gfs.private.fabricam.com*" }).mainwindowtitle

$Cipher = get-content $CipherFile | ConvertTo-SecureString
$Pass = (New-Object PSCredential "user", $Cipher).GetNetworkCredential().Password

Send-Keys -ApplicationTitle $GFSTitle -Keys "$ENV:USERDOMAIN\$EnV:USERNAME`t$Pass`r"

Clear-Variable Pass, Email


* Set the proxy server name to your environment Proxy server web name.

This is used in the include so it must be in the same DIR.

Once I worked the bugs out it, it works like a charm. and I created a Shortcut on the desktop to link to the script to go and open Azure for me.

It may take a little tweaking in your environment. Your proxy server may have a different name, and I did edit this sample to a fictitious company.

I did some password encryption to securely store the Proxy server password. To keep the security wonks off my case.


Wednesday, May 1, 2019

Powershell + Devops Global Summit 2019

I am here at the summit and its great!
YouTube: PowerShell Devops Summit report 1
The first day was opening keynote speeches

First up wall Will Anderson and he covered the welcome and introduction to the conference.
he did great with covering what we needed to know about the con.

then we got blown away by the powerhouses, Don Jones and Jeffry Snover.

Here is a link to my first video report.  It's going to be impromptu, no editing but I hope you enjoy it.

here is the first video3
LINK:  PowerShell Devops Summit report 1

LINK: PowerShell Devops Summit 2019 - report 2

LINK:   PowerShell Devops Summit 2019 report 3

LINK:  PowerShell Devops Summit 2019 report 4




Tuesday, January 8, 2019

IBM WebSphere MQ PowerShell SnapIn

I found myself responsible for the operation of some servers that use IBM WebSphere MQ.
Slowly over time, my manager thinking that another team was responsible for the operation of the software, and would provide all the technical support for the product. So he instructed me to stay hands off on the software. Just maintain the os and the IIS components. 

Well, for better or worse, the IBM software was fairly stable, but over time, issues like memory leaks required us to restart the web app pool. More issues came up demanded answers from management, and the support team that was to take care of WebSphere MQ dissolved quietly. While a few staff that new the product remained, they moved off to development products. Another engineer left the company. So I was left the SME on the product. So.. I had to become more familiar with the Product and to support the new engineer and the team that took over the MQ support for the system. I needed a health check for the product to help understand what it was configured and how it was performing. 
So did my research and I found that IBM had published a snapin for the product, and was still supporting it. I Know PowerShell, and that module was very priceless in figuring out what the configuration was doing. 

Here I share my experiences with installing Powershell Support for IBM WebSphere MQ.

The 32-bit installer is simple.
However, the 64-bit version is a bit cryptic.

The wonderful module that IBM provided can be found:
LINK: MO74: WebSphere MQ - Windows PowerShell Library

Install file in the zip.:
  • Unzip the downloaded file:  mo74_v2.0.1.zip to a work directory/folder on your target computer. 
  • Open the work folder, and switch to the sub folder/directory:  \mo74_v2.0.1.zip\mo74_v2.0.1\mo74_v2.0.1_x86_x64
  • RUN the installer: setup.exe

Follow the standard GUI install process. (AKA the forehead install. )

There is a directory created by default in:

  • C:\Program Files (x86)\IBM\PowerShell for WebSphere MQ

This contains files you need for 64 Bit support.
Now, WHY would you want 64-bit support???
Well, most servers these days are 64-bit, and the Remote Powershell stuff on a 64-bit computer uses the 64 bit Powershell version. and the Snapin installs in only the 32-bit version of PowerShell.

You can use this following PowerShell script to install the WebSphereMQ 64-bit support snapin.

Script:
$path = "c:\Program Files\WindowsPowerShell\Modules\WebSphereMQ\"

mkdir $path -Verbose -ErrorAction SilentlyContinue

COPY "C:\Program Files (x86)\IBM\PowerShell for WebSphere MQ*" $path

CD $path

"Change Dir to: $PWD"


$DLLS = GCI *.dll

$FWInstall =
    gci C:\Windows\Microsoft.NET\Framework64\v4.* `
        -Recurse -Filter "InstallUtil.exe"
    #Line wraped with backtick.
& $FWInstall.FullName $DLLS

#Save the current value in the $p variable.
$p = [Environment]::GetEnvironmentVariable("PSModulePath")

#Add the new path to the $p variable. Begin with a semi-colon separator.
$p += ";$PWD"

#Add the paths in $p to the PSModulePath value.
[Environment]::SetEnvironmentVariable("PSModulePath", $p)
* you can use this code and the contents of the dir and install as part of a server build script. 

The installer program provided with .NET is verbose and will tell you how the process of registering the DLL's goes. 

Snapin is loaded with the following:
Add-PSSnapIn IBM.PowerShell.WebSphereMQ

You can check to see if the commands have been added with the following command


Get-Command *WMQ*


>> How to use all these nifty new commands is Subject of another article. 

Wednesday, September 19, 2018

Coloring in a HTML table for readablity.

When I first started doing health checks, I wanted to get the results to have some color.
I found a suggestion that the color codes could be added after. So I set up the testing script to put key words in the answers in the table and then after the table is converted to  HTML use a search and replace to substitute the HTML tags that would change the table color.

The first part is code from Microsoft that give the basic table design. 
The second part creates some headers and footers, and then creates the HTML table block for the message.
The Third part colors the table with HTML tags, using a replace command.
The final section assembles all the pieces into the final HTML document.



#HTML Header
$H = "<html>
    <style>
        BODY{background: # CAD3CC; font-family: Arial; font-size: 8pt;}
        H1{font-size: 16px;}
        H2{font-size: 10px;}
        H3{font-size: 12px;}
        H3.Pass{color: green}
        H3.Fail{color: red}
        TABLE{border: 1px solid black; border-collapse: collapse; font-size: 8pt;}
        TH{border: 1px solid black; background: #dddddd; padding: 5px; color: #000000;}
        TD{border: 1px solid black; padding: 5px; }
        td.Pass{background: #7FFF00;}
        td.Warn{background: #FFE600;}
        td.Fail{background: #FF0000; color: #ffffff;}
        </style>
    "


# Labels for HTML
$T = "<H1>Prod Application test</H1><BR>"
$B = $T + "<H2>Non-Prod Application test $Healhcheck " + $Warning + 
      "<H2><br> This is a test for Application servers <br><P> </H2> "
If ($E) { 
      $EReport = '<H1> <font color="red">ERROR REPORT:</H2></font><P><BR><BR> ' 
        }
$PostContent = "$EReport $E <BR>This report was generated on server $ENV:COMPUTERNAME <p>"
$DataReport = $Report | ConvertTo-Html -Fragment

#Crayon coloring code
#Coloring crayon the table.
$B += (($DataReport -replace "<td>Fail ", '<td class="Fail">') 
          -replace "<td>Pass ", '<td class="Pass">') 
          -replace "<td>Warn ", '<td class="Warn">'


#Now form the code into a final web page for emailing.


$Body = ConvertTo-Html -Head $H -Title $T -body $B -PreContent $PostContent



Start a scheduled task with a GUI menu.

Want to make a script run under other credentials?

You can create a scheduled task. Which can be fired off from a menu.

The menu script is below.
it takes advantage of the cool Out-GridView command.

$task = $true
While ($task)
{
    Write-host "Looking up available Healthchecks" -ForegroundColor Green
    Clear-Variable task
    Get-ScheduledTask -TaskPath "\AdminTasks\" |
    Select TaskName, State, Description |
    Out-GridView -OutputMode Multiple |
    foreach{
        if ($_)
        {
            $_ |
            Get-ScheduledTask |
            Tee-Object -Variable task |
            Start-ScheduledTask
            $task |
            Get-ScheduledTask
        }
    }
}


Wednesday, September 12, 2018

Parallel PowerShell - Part 3

Speaking of making code go faster...


I learned at the PowerShell Summit this year from Joshua King that doing repetitive tasks or loops one way may be quite a bit slower than doing it one way vs another. I learned that functions get compiled by the PowerShell engine, and don't continue to get interpreted.  I do recommend his presentation to understand how he did his research and validation. Whip Your Scripts into Shape: Optimizing PowerShell for Speed

This I had done without realizing the performance improvement is provided. It was chosen to work better with the Workflow process.

It appears that Workflows get compiled by the interpreter, and get the same speed up.  So these options are Good methods to speed things up. Workflows give the capability to run things in parallel.  Using functions within the workflow the method I used to use the parallel functions of Workflow and made the code easier to write and less restrictive. 

But back to my original story. 
One of the things I was concerned about was, what would happen if the server I tasked to do part of the testing, didn't respond for some reason. Would my Health Check crash? return a big red error? or worse. just stop dead and hang the script with no return. 
Fortunately, I haven't had a script zombie yet doing this in the parallel version of the script. But it was a plague in the previous versions. (a zombie is a script that never stops, waiting indefinitely. )
I did make sure to incorporate timeout settings on the web calls to ensure that the computer would not wait forever for a return. There were other checks that would get hung, so I made sure to verify the server was functioning properly before I ran those.  This seems to be where my scripts get stuck. 

The problem became running tasks in parallel, was what would happen if the server was off or nonresponsive. Fortunately, the parallel requests didn't hang like the previous versions. They did the opposite, they returned nothing.

So I had to devise a method to discover which tests had not returned. So I winced and then tried for a Jimmy Neutron brain blast...  that didn't work.
I tried things and came up with a loop that would check to see if each item in the original list of servers to test was in the results.

One approach was to review the errors in the shell variable  $ERROR.  but that didn't work out in some cases.
So to get a full picture, I found that comparing the list of servers submitted with the resulting Responses.


$Missing = $Servers | ?{ $result.PSComputerName -notcontains $_ }


So this gives us the ability to create some additional entries of the response to mark the missing responses.

$MissingServers = $Missing | foreach {
    $MissingServer = @{
        "URI"               = "https://$($_):443/App/Service.svc?wsdl";
        "StatusCode"        = "Fail 00";
        "StatusDescription" = "Fail N/A";
        "Result1"           = "N/A";
        "Result2"           = "N/A s"
        }
    New-Object -TypeName PSObject -Property $MissingServer
    } #Close foreach

So you can combine your results and get a complete table with :

$Result += $MissingServers

Where $Result is the results of the successful test.