Showing posts with label PowerShell. Show all posts
Showing posts with label PowerShell. Show all posts

Monday, August 17, 2020

Set-WinRMCert Script to easily set the Certificate for remote PowerShell

 I had to figure out from articles on the web how to set up Remote PowerShell to use SS:/HTTP

It was a PITA. 

I came up with this script recently to automate the task. 

It assumes that you already have a certificate loaded on the computer in the usual location that we put out computer certs.   "Cert:\LocalMachine\My"  If you put your cert in some different spot in the CERT: store, you will need to adjust this path. 

One important thing is that when you want to remote to a computer over SSL/https  you must connect with the FQDN.   So no shortcut, you need to do something like:

  • ' Enter-PSSession -UseSSL -ComputerName  Server01.famricam.com '

Running this script is only needed to be done once.  Assuming you get a success. 
Until your certificate expires. then you will need to re-run it. 

Here is the script. 

Set-WinRMCert.ps1

<#  
    .NOTES
    ===========================================================================
     Created with:  SAPIEN Technologies, Inc., PowerShell Studio 2020 v5.7.179
     Created on:    8/13/2020 10:15 AM
     Created by:    Richard Stoddart
     Filename:      Set-WinRMCert.ps1
    ===========================================================================
    .DESCRIPTION
        Enables Remote PS (WinRM) SSL HTTPS service.
        Sets certificate to default WinRM  port. Port 5986
#>

#Requires -RunAsAdministrator
#enable WinRM HTTPS service
& winrm quickconfig -transport:https -q
Start-Sleep -Seconds 2

#get Certificate
$CertPath = "Cert:\LocalMachine\My"
$cert = ((Get-ChildItem $CertPath | Sort-Object NotAfter )[-1] )
if (!$cert) { Write-error "Certificate not found in $CertPath "; return }

# Create text for CMD file
'CSCRIPT ' +
$env:SystemRoot +
'\System32\winrm.vbs ' + 
'set winrm/config/Listener?Address=*+Transport=HTTPS @{Hostname="'+
$Cert.FriendlyName + 
'";CertificateThumbprint="' + 
$cert.Thumbprint +
'"}' |
Out-File -FilePath .\TempSetWinRM.cmd -Encoding oem

# Add below line Will turn off the HTTP WinRM port if not controled by GPO
# + "`n" +'winrm set winrm/config/Listener?Address=*+Transport=HTTP @{Enabled="false"}'

# Execute TempSetWinRM.CMD file
$Out = & .\TempSetWinRM.cmd

#vailidate config worked, catch error
$CertInstalled =
    (($out | ? { $_.trim() -like "CertificateThumbprint*" }).split("=")[1]).trim()

If ($CertInstalled -eq $cert.Thumbprint)
    { Write-Output "Sucess: Certificate $($cert.Thumbprint) $($Cert.Subject)" }
Else { Write-Error $out[0];  return}
Write-Output "`n"

#Output WinRM settings
Write-Output "Winrm Setting results `n --------------------------"

& Winrm enumerate winrm/config/listener

Remove-Item -Path '.\TempSetWinRM.cmd'

#GI WSMan:\localhost\Service\CertificateThumbprint | Set-Item -Value ""



END

Friday, June 14, 2019

HTTPS Cert Expired and I don't care

Cert expiration is the bain of web administrators and Internet Web Properties.
use to be, you had to pay richly for the grand privilege of having a certificate on your website.
Now it just a matter of course.

Use this PowerShell incantation to set the "I Don't Care" on the certificate checking code.


[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }


Yes, I know it is not secure now, but I need to get to the site for testing or whatever, and I am willing to accept a connection to allow me to do what I need. 

* Use of course at your own risk. 

Enable Proxy server settings in PowerShell

proxy servers don't like you to go straight to the internet.

you get an error something like:

Invoke-WebRequest :
This Page Cannot Be Displayed
Authentication is required to access the Internet using this system. A valid user ID and password must be entered when prompted.

so you need to give this Powershell Incantation

#Proxy
$wc = New-Object Net.WebClient
    $wc.UseDefaultCredentials = $true
    $wc.Proxy.Credentials = $wc.Credentials

You can guess from this that you can actually set proxy credentials with this. But I haven't worked that out yet.

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, April 27, 2018

Powershell Escape characters.

A while back I couldn't find a definitive list of the regular escape characters for PowerShell. So I wrote a program that would generate them all and give me a clue for each letter what I might get.

I have since lost the code, and the output was a little cryptic, particularly with nonprinting characters like Tab, space, Carriage return, Line feed, and Bell.

The Bell character "`a" was interesting. But it doesn't always make it back to me from a session.

The first 2 are for the quoting characters, if you need to embed a quote in the string you are creating, this is one easy way to get them placed literally, and not interpreted by the compiler.

As it was noted it the PluralSight Gotcha video, these are limited to Powershell, you will find if you pass a string to .net or some other software, it may have a different escape character, and different behavior.


Notes:
  • Single quote ' means that what is enclosed is Literal not to be processed
  • Double quote " means that what is enclosed is interpreted.
  • The Backtick is ` and not the single quote '  (apostrophe)
  • The key is typically on the left side of the keyboard upper left corner. 

PowerShell Escape character table:

ASCII
Letter
Esc
Name
Result ASCII
34
"
`"
Double Quote
34
39 
' 
`'
Single Quote
39
48
0
`0
Null
00
96
`
``
Back-tick
96
97
a
`a
Bell
07
98
b
`b
Backspace
08
102
f
`f
Line Feed
12
110
n
`n
New Line
10
114
r
`r
Carriage Return
13
116
t
`t
Tab
09
118
V
`v
Vertical tab
11

*   They are Case Sensitive...  "`n" -ne  "`N"  etc. 


Monday, April 23, 2018

Out-Internet_explorer

Output to a web browser? But why?
I was fishing around in the PowerShell Studio Snippets and a ran across one Snippet:called Trace.

I wanted to use this snippet to upgrade the output of my troubleshooting tool, ServerPulse. An update of a script that I originally wrote to give text output. With this connection to Internet Explorer, I could create something that was a bit easier on the eyes and stop the junior engineers from puckering when they looked at it. ServerPulse was a text-based self-updating dashboard which I thought was rather functional. however, I could see a bit of aesthetics to making it browser output.  I think there is a lot of possibilities with formatting the output as HTML and then it could be delivered by file, email,  or to a web browser.

This update would give me time to rethink what and how I was gathering the data. Keeping the live data refreshing feature of the troubleshooting tool would be important.

I did some tweaking on the base snippet.

I played with this on my workstation, and when I tried it on a server I got some weird errors.

Problem is this requires a certain DLL to function - "Microsoft.mshtml.dll"
It may not be loaded on a server or workstation in some conditions. I have read that MS office installs it.  Here is a more detailed article in how to add it if you get the error "Property 'innerhtml' cannot be found on this object; make sure it exists and is settable."
Check out - http://www.dlldownloader.com/microsoft-mshtml-dll/ with a detailed explanation of the problem.

After fixing that, I was able to use it any computer that had the dll, I read that the Microsoft Office suite added this dll, which was the cause of the initial confusion with the server version, Which had no reason for it to have MS office installed.

So I created the following function from the snippet to post things to the Web page. You can repeatedly call this function to update information if you want to refresh or expand on the output. The flexibility of the Web browser interface is almost without limit.

But... You have to feed it HTML.
Besides hello world, I thought a basic clock would be in order.
Clock code to HTML A little adjustment to the function like so:
And when feed the output the clock code to the function it pops up a window like this:
" Out-IE ($report) "

IE WINDOW:

Hard to look at and kind of cryptic. But re-using some old MS script example, I can append a block of formatting to make it a little prettier.

* NOTE: If your playing with this on the Shell prompt, Make sure you get the $IE = ""In there someplace between sessions or you won't get a new window...  which was confusing at first for me.
And this is a feature for being able to update the data.

The Refined  IE output portion now looks like:




Now some more example of use.

Building on that code I added another table and gleaned some additional info from the local system. Then you can loop the code to keep it updating the output on IE. The next step was to add some more useful info: And I added some more useful info. An example finished script:

Output of this looks like:


And this version updates the info on the screen, you can see the values change, and the clock ticking.

Wednesday, April 18, 2018

Formatting Output in KB, MB, GB, TB ....

One of the things that bugged me about PowerShell since I first worked with it was its penchant to give me File directory listings with the file length in bytes. DIR in the CMD shell did it for me.

The textbook answer, of course, is to simply divide the output by 1KB, 1MB, 1GB  as these constants are set in the environment. The obvious problem with this is that it makes the assumption you know what size you're going to get. or that you want the answer in all the same units. But what if you have limited space to display the info, and you don't want to put  23B in the same column with 1293834556 in the same column.

So recently I set about to find a way to have a function that would auto-scale the Byte prefix. I played with the various number types available and put it to the test to see how high I could go with the prefixes. A list I got from Wikipedia.

Experimenting, I worked out an algorithm for this, and it should work cross-platform.
I will update this when I hear of it being tested in something other than Windows Power Shell (WPS). I created these 2 functions, one to work with KB and the second to work with standard SI 1000 units. The second is just a bonus from figuring out the byte calculations.

I added a few features to the function to make it more flexible in use. I added the "-digits" switch so you could control how many decimal places you got on the output. and I also added the "-Units" switch so that you could change from the default "B" to Bytes or whatever fits your need.

I then wracked my brain with what to call it.
Having watched SAO – Ordinal Scale. On Blu-ray with my wife recently, I looked up Ordinal and it seems to fit. Prefix would also work, but that may have other implications.

While I was tweaking it for this article I thought I could make a minor change and have it do the same autoscale for regular 1000 based items. So this could also be used to deal with anything from Dollars to  Miles or anything you have to describe a large number of.

If you new to functions, you can incorporate this code into your script, or you can load it into memory.  This is called Dot sourcing. Google 'Dot source PowerShell function'

Convert-kBOrdinal.ps1

<#  
    .NOTES
    ===========================================================================
     Created with:  SAPIEN Technologies, Inc., PowerShell Studio 2018 v5.5.150
     Created by:    Rich Stoddart
     Filename:     Convert-kBOrdinal.ps1    
    ===========================================================================
    .DESCRIPTION
        Functions to format output by standard Metric Prefixes for binary (1024) 
        and decimal (1000) units. 
        Created to format data concisely on reports, 
        this will process things to as large a number you can hold in a [decimal] 
        type. 
    .EXAMPLE
        gci |% { New-Object -TypeName PSObject -Property ( @{Length = ($_.Length | Convert-kBOrdinal) ; Name = $_.Name}})
        (gi .\install.exe ).length | Convert-kBOrdinal
#>

function Convert-kBOrdinal
{
    param (
        [Parameter(ValueFromPipeline, Position = 0, Mandatory = $true)]
        [decimal]$Num,
        [Parameter(Position = 1, Mandatory = $false)]
        [int]$digits = 2,
        [Parameter(Position = 2, Mandatory = $false)]
        [string]$Units = "B"
    )
    
    if ($NUM -lt 1E+28)
    {
        [int]$Ordinal = ([math]::Floor((($Num.ToString()).Length - 1)/ 3))
        [string]$Digit = [math]::Round($Num / [math]::pow(1024, $Ordinal), $digits)
        [string]$Suffix = "$(((' KMGTPEZYB').Substring($Ordinal, 1)).Trim())$Units"
    }
    Else { "OverRange" }
    return "$Digit$Suffix"
}

function Convert-kOrdinal
{
    param (
        [Parameter(ValueFromPipeline, Position = 0, Mandatory = $true)]
        [decimal]$Num,
        [Parameter(Position = 1, Mandatory = $false)]
        [int]$digits = 2,
        [Parameter(Position = 2, Mandatory = $false)]
        [string]$Units
    )
    
    if ($NUM -lt 1E+28)
    {
        [int]$Ordinal = ([math]::Floor((($Num.ToString()).Length - 1)/ 3))
        [string]$Digit = [math]::Round($Num / [math]::pow(1000, $Ordinal), $digits)
        [string]$Suffix = "$(((' KMGTPEZYB').Substring($Ordinal, 1)).Trim())$Units"
    }
    Else { "OverRange" }
    return "$Digit$Suffix"
}