<#
.SYNOPSIS
    Generates a Certificate Signing Request based on values inputted.  Any values not inputted will result in the use of default values.
.DESCRIPTION
    Generates a Certificate Signing Request based on values inputted.  Any values not inputted will result in the use of default values.  CSR will be printed to the screen, but can be saved to the clipboard, or to a file.
    Default values are:

.NOTES
    Run as administrator is required.
.EXAMPLE
    New-ITDSslCertificateSigningRequest -CommonName 'commonname.nd.gov'
    CSR is generated using the common name shown, and default values for everything else
.EXAMPLE
    New-ITDSslCertificateSigningRequest -CommonName 'commonname.nd.gov' -Organization "OrgNameHere" -OrganizationalUnit "OrgUnitHere" -Locality Mandan -State ND -Country US -KeyLength 4096
    CSR is generated using the values specified, defaults for the rest
.EXAMPLE
    New-ITDSslCertificateSigningRequest -CommonName 'commonname.nd.gov' -Organization "OrgNameHere" -OrganizationalUnit "OrgUnitHere" -Locality Mandan -State ND -Country US -KeyLength 4096 -ToClipboard
    CSR is generated using the values specified, defaults for the rest, and saved into the user's clipboard
.EXAMPLE
    New-ITDSslCertificateSigningRequest -CommonName 'commonname.nd.gov' -ToPath C:\temp.csr
    CSR is generated using the common name shown, and default values for everything else, and saves the CSR to a local path
#>

function New-ITDSslCertificateSigningRequest {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [string]
        $CommonName,

        [string]
        $Organization = "State of North Dakota",

        [string]
        $OrganizationalUnit = "NDIT",

        [string]
        $Locality = "Bismarck",

        [string]
        $State = "ND",

        [string]
        $Country = "US",

        [ValidateSet(2048, 4096)]
        [int]
        $KeyLength = 4096,

        [switch]
        $Exportable = $true,

        [ValidateSet('sha256','sha384','sha512','md5')]
        [string]
        $HashAlgorithm = "sha256",

        [switch]
        $ToClipboard,

        [string]
        $ToPath
    )
    
    begin {
        if (-NOT([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
            Write-Host "Administrator priviliges are required. Please restart this script with elevated rights." -ForegroundColor Red
            Pause
            Throw "Administrator priviliges are required. Please restart this script with elevated rights."
        }
    }
    
    process {
        $UID = [guid]::NewGuid()
        $files = @{}
        $files['settings'] = "$($env:TEMP)\$($UID)-settings.inf";
        $files['csr'] = "$($env:TEMP)\$($UID)-csr.req"

        $request = @{}
        $request['SAN'] = @{}

        #2048, sha256
        $settingsInf = "
[Version] 
Signature=`"`$Windows NT`$ 
[NewRequest] 
KeyLength =  {{KeyLength}}
Exportable = {{Exportable}} 
MachineKeySet = TRUE 
SMIME = FALSE
RequestType =  PKCS10 
ProviderName = `"Microsoft RSA SChannel Cryptographic Provider`" 
ProviderType =  12
HashAlgorithm = {{HashAlgorithm}}
;Variables
Subject = `"CN={{CN}},OU={{OU}},O={{O}},L={{L}},S={{S}},C={{C}}`"
[Extensions]
{{SAN}}
;Certreq info
;http://technet.microsoft.com/en-us/library/dn296456.aspx
;CSR Decoder
;https://certlogik.com/decoder/
;https://ssltools.websecurity.symantec.com/checker/views/csrCheck.jsp
"

        
        $request['SAN_string'] = & {
            if ($request['SAN'].Count -gt 0) {
                $san = "2.5.29.17 = `"{text}`"
"
                Foreach ($sanItem In $request['SAN'].Values) {
                    $san += "_continue_ = `"dns=" + $sanItem + "&`"
"
                }
                return $san
            }
        }

        $settingsInf = $settingsInf.Replace("{{CN}}", $CommonName)
        $settingsInf = $settingsInf.Replace("{{O}}", $Organization)
        $settingsInf = $settingsInf.Replace("{{OU}}", $OrganizationalUnit)
        $settingsInf = $settingsInf.Replace("{{L}}", $Locality)
        $settingsInf = $settingsInf.Replace("{{S}}", $State)
        $settingsInf = $settingsInf.Replace("{{C}}", $Country)
        $settingsInf = $settingsInf.Replace("{{SAN}}", $request['SAN_string'])
        $settingsInf = $settingsInf.Replace("{{KeyLength}}",$KeyLength)
        $settingsInf = $settingsInf.Replace("{{HashAlgorithm}}",$HashAlgorithm)
        $settingsInf = $settingsInf.Replace("{{Exportable}}",$Exportable)

        # Save settings to file in temp
        $settingsInf > $files['settings']

        certreq -new $files['settings'] $files['csr'] > $null

        $CSR = Get-Content $files['csr']

        Write-Output $CSR
        If ($ToClipboard) {
            $CSR | Set-Clipboard
        }
        If ($ToPath) {
            $CSR | Out-File -FilePath $ToPath
        }

        $files.Values | ForEach-Object {
            Remove-Item $_ -ErrorAction SilentlyContinue
        }

        
    }
    
    end {
        
    }
}