20 August 2020

Bulk create certificates from .CSR to .CER with root and intermediate included with PowerShell (quick and dirty)

This script was born after I needed to create over 200 certificates requested by .csr files.

The regular way of pasting the content of the .csr into the certsrv site was to time consuming, boring and repetitive to do by hand.

But I couldn't find a script or method that would work for what I needed.

I had hoped that the famous PSPKI module by Vadims Podāns (https://www.pkisolutions.com/tools/pspki/) could help me out, and in a way it could but not entirely how I wanted it. Turned out the "foreach" I tried couldn't pass trough the "Submit-CertificateRequest" commandlet.

So this is what I came up with it requires some Notepad++ find and replace, it's a bit quick and dirty but does the job.

If somebody knows how to make this better, please drop a message.

It requires the PSPKI, found here or from PowerShell: 

Install-Module -Name PSPKI

The script:
Import-Module pspki            
            
cd C:\Scripts\Get-CertificateFromCSR\csr            
            
$PKI = "YourCAServer.domain.lan"            
$OutPath = "C:\Scripts\Get-CertificateFromCSR\IssuedCertificates"            
            
$status = Submit-CertificateRequest -path "C:\Scripts\Get-CertificateFromCSR\CSR\Certificate01.csr" -CA $PKI -Attribute "CertificateTemplate:Webserver"             
$ReqID = $status.requestid            
Get-IssuedRequest -RequestID $reqID -CertificationAuthority $PKI | Receive-Certificate -Path $OutPath\Certificate01 -Force            
cd $outpath\Certificate01            
$item = ls            
Rename-Item -path $item -newname Certificate01.cer            
$status = Submit-CertificateRequest -path "C:\Scripts\Get-CertificateFromCSR\CSR\Certificate02.csr" -CA $PKI -Attribute "CertificateTemplate:Webserver"             
$ReqID = $status.requestid            
Get-IssuedRequest -RequestID $reqID -CertificationAuthority $PKI | Receive-Certificate -Path $OutPath\Certificate02 -Force            
cd $outpath\Certificate02            
$item = ls            
Rename-Item -path $item -newname Certificate02.cer

Etc, etc, etc

04 June 2020

How to create key file and certificate file from pfx - Openssl

Install the Windows version of Openssl from:
https://slproweb.com/download/Win64OpenSSL-3_1_2.msi

Open a command prompt window in c:\Program Files\OpenSSL\Bin
(or even better, add Openssl to your Path)

Then type:

For the key file:
openssl pkcs12 -in [yourfile.pfx] -nocerts -out [keyfile-encrypted.key]
Example:
openssl pkcs12 -in c:\temp\mycertificate.pfx -nocerts -out c:\temp\keyfile-mycertificate.key

You will be asked for the pfx password (import password), and then asked to enter a password for the .key file (PEM pass phrase)

For the certificate:
openssl pkcs12 -in [yourfile.pfx] -clcerts -nokeys -out [certificate.crt]
Example:
openssl pkcs12 -in c:\temp\mycertificate.pfx -clcerts -nokeys -out c:\temp\certificate-mycertificate.crt

You will only be asked for the pfx password (import password) since the private key will not be exported.

And for .pfx to .pem

openssl pkcs12 -in file.pfx -out file.nokey.pem -nokeys 

openssl pkcs12 -in file.pfx -out file.withkey.pem

Convert x509 to PEM

openssl x509 -in certificatename.cer -outform PEM -out certificatename.pem



Convert PEM to DER

openssl x509 -outform der -in certificatename.pem -out certificatename.der



Convert DER to PEM

openssl x509 -inform der -in certificatename.der -out certificatename.pem

Convert PEM to P7B

Note: The PKCS#7 or P7B format is stored in Base64 ASCII format and has a file extension of .p7b or .p7c.
A P7B file only contains certificates and chain certificates (Intermediate CAs), not the private key. The most common platforms that support P7B files are Microsoft Windows and Java Tomcat.

openssl crl2pkcs7 -nocrl -certfile certificatename.pem -out certificatename.p7b -certfile CACert.cer



Convert PKCS7 to PEM

openssl pkcs7 -print_certs -in certificatename.p7b -out certificatename.pem



Convert pfx to PEM

Note: The PKCS#12 or PFX format is a binary format for storing the server certificate, intermediate certificates, and the private key in one encryptable file. PFX files usually have extensions such as .pfx and .p12. PFX files are typically used on Windows machines to import and export certificates and private keys.

openssl pkcs12 -in certificatename.pfx -out certificatename.pem



Convert PFX to PKCS#8
Note: This requires 2 commands

STEP 1: Convert PFX to PEM

openssl pkcs12 -in certificatename.pfx -nocerts -nodes -out certificatename.pem



STEP 2: Convert PEM to PKCS8

openSSL pkcs8 -in certificatename.pem -topk8 -nocrypt -out certificatename.pk8



Convert P7B to PFX
Note: This requires 2 commands

STEP 1: Convert P7B to CER

openssl pkcs7 -print_certs -in certificatename.p7b -out certificatename.cer



STEP 2: Convert CER and Private Key to PFX

openssl pkcs12 -export -in certificatename.cer -inkey privateKey.key -out certificatename.pfx -certfile  cacert.cer
Or:
openssl pkcs12 -export -out domain.name.pfx -inkey domain.name.key -in domain.name.crt
Or with intermediate and root:
openssl pkcs12 -export -out domain.name.pfx -inkey domain.name.key -in domain.name.crt -in intermediate.crt -in rootca.crt

27 May 2020

How to create a shared mailbox from hybrid Exchange directly in Exchange Online but also visible in on-premises Active directory

How to create a shared mailbox from hybrid Exchange directly in Exchange Online but also visible in on-premises Active directory
Now that's a mouthful, but a question that's asked often.
And that's not strange at all, because after moving most of your mailboxes to Exchange Online, the inevitable new shared mailbox request will pop up.

Only to find out that if created in the old way you need to manually move it Exchange Online.

And if you create shared mailbox in the ECP you will soon find that you problably made the wrong choice and the new mailbox is not visible in your on-premises Active Directory.

There's where this script comes to the recue.
It creates a remote shared mailbox, a distribution group for full access and send-as rights, adds that group to the mailbox, hides the distribution group because we only use it for access rights.
Then login to Exchange Online, disable POP, IMAP, Activesync and OWA, and resets the proxy settings if neccesary.

This can also be used to create usermailboxes, just tweak it to your needs.
It's also on my Github: https://github.com/brenkster/New-RemoteSharedMailbox

param ($Alias,$DisplayName)

#	Show countdown timer
           
Function Start-Countdown
{
    Param(
        [Int32]$Seconds = 600,
        [string]$Message = "Waiting for 10 minutes"
    )
    ForEach ($Count in (1..$Seconds))
    {   Write-Progress -Id 1 -Activity $Message -Status "Waiting for $Seconds seconds, `
$($Seconds - $Count) left" -PercentComplete (($Count / $Seconds) * 100)
        Start-Sleep -Seconds 1
    }
    Write-Progress -Id 1 -Activity $Message -Status "Completed" -PercentComplete 100 -Completed
}



#	Load Exchange Powershell module
#add-pssnapin Microsoft.Exchange.Management.PowerShell.E2010
add-pssnapin Microsoft.Exchange.Management.PowerShell.SnapIn
#	Load Active Directory Powershell module
import-module activedirectory
            
# Setup variables
$DomainController="servername.domain.lan"
$OU='domain.lan/Groups/Mail/Shared Mailboxes'
$OU2='domain.lan/Groups/Mail/Shared Mailbox Groups'
$UPNdomain = "@domain.nl"
$UPNRemoteDomain = "@domain.onmicrosoft.com"



if ($Alias)
{
    if ($Alias.Contains('@')) { $Alias = $Alias.Substring(0,$Alias.IndexOf('@')) }
    $AliasMailbox = Get-Mailbox $Alias -ErrorAction SilentlyContinue
    $AliasMailUser = Get-MailUser $Alias -ErrorAction SilentlyContinue
    if ($AliasMailbox -or $AliasMailUser)
    {
        Write-Host "The Alias specified already exists" -ForegroundColor red
        $Alias = $null
    }
}
while (!$Alias)
{
    $Alias = Read-Host -Prompt "Alias (max 20 caracters)"
    if ($Alias)
    {
        if ($Alias.Contains('@')) { $Alias = $Alias.Substring(0,$Alias.IndexOf('@')) }
        $AliasMailbox = Get-Mailbox $Alias -ErrorAction SilentlyContinue
        $AliasMailUser = Get-MailUser $Alias -ErrorAction SilentlyContinue
        if ($AliasMailbox -or $AliasMailUser)
        {
            Write-Host "The Alias specified already exists" -ForegroundColor red
            $Alias = $null
        }
    }
}

if ($DisplayName)
{
    $DisplayNameMailbox = Get-Mailbox $DisplayName -ErrorAction SilentlyContinue
    $DisplayNameMailUser = Get-MailUser $DisplayName -ErrorAction SilentlyContinue
    if ($DisplayNameMailbox -or $DisplayNameMailUser)
    {
        Write-Host "The Display Name specified already exists" -ForegroundColor red
        $DisplayName = $null
    }
}
while (!$DisplayName)
{
    $DisplayName = Read-Host -Prompt "Display Name (As many caracters as you like)"
    if ($DisplayName)
    {
        $DisplayNameMailbox = Get-Mailbox $DisplayName -ErrorAction SilentlyContinue
        $DisplayNameMailUser = Get-MailUser $DisplayName -ErrorAction SilentlyContinue
        if ($DisplayNameMailbox -or $DisplayNameMailUser)
        {
            Write-Host "The Display Name specified already exists" -ForegroundColor red
            $DisplayName = $null
        }
    }
}

# Setup more variables
$Alias=$Alias.ToLower()
$UPN=$Alias + $UPNDomain
$UPNRemoteRoutingAddress = $Alias + $UPNRemoteDomain

Sleep 10
# Create the SharedMailbox
Write-Host "Creating Shared Mailbox" -ForegroundColor green            
New-RemoteMailbox -RemoteRoutingAddress "$UPNRemoteRoutingAddress" -Shared -UserPrincipalName "$UPN" `
-OnPremisesOrganizationalUnit $OU -Alias $alias -Name $alias -DisplayName $displayname `
-PrimarySmtpAddress $UPN -SamAccountName $alias -DomainController $domaincontroller            
Write-Host "Created Shared Mailbox" -ForegroundColor green            
            
Sleep 10            
# Set the description for the SharedMailbox            
Write-Host "Set Description" -ForegroundColor green            
Set-ADUser $Alias -Description "Shared Mailbox t.b.v. $Displayname"            
Write-Host "Description set" -ForegroundColor green            
            
Sleep 10            
# Create the distributiongroup for security use            
Write-Host "Creating Office365 Distributiongroup" -ForegroundColor green            
New-DistributionGroup  -DisplayName "SM.$alias" -Type Security -Alias "SM.$alias" -Name "SM.$alias" -Organizationalunit $OU2            
Write-Host "Office365 Distributiongroup created" -ForegroundColor green            
            
Sleep 10            
# Hide distributiongroup            
Write-Host "Set Office365 distributiongroup hidden" -ForegroundColor green            
Set-DistributionGroup -Identity "SM.$alias" -HiddenFromAddressListsEnabled:$true            
Write-Host "Office365 distributiongroup set to hidden" -ForegroundColor green            
            
Sleep 30            
# Sync AADConnect and wait for the account to show up online            
Write-Host "Starting Adsynccycle now" -ForegroundColor red            
Invoke-Command -ComputerName servername.domain.lan -Port 5986 -UseSSL -ScriptBlock { Start-ADSyncSyncCycle -PolicyType Delta }            
Write-Host "Adsynccycle has run" -ForegroundColor green            
            
Write-Host "Waiting for AzureAD sync" -ForegroundColor green            
#Start-Countdown -Seconds 600 -Message "Waiting for 10 minutes"            
            
$Time = 600            
$i = 0            
Do {            
    $i++            
    Write-Progress -Activity 'Waiting for 10 minutes' -Status 'Status' -PercentComplete (($i/$Time)*100) -SecondsRemaining ($Time-$i)            
    Start-Sleep 1            
} Until ($i -eq $Time)            
            
# Set the PowerShell session to use the proxy            
netsh winhttp set proxy proxy.domain.lan:8080            
Write-Host "Proxy Set" -ForegroundColor green            
            
# Connect to ExchangeOnline PowerShell            
Connect-ExchangeOnline -ShowProgress $true            
Write-Host "Connected to ExchangeOnline" -ForegroundColor green            
            
# Disable Mailbox features            
Write-Host "Disabeling OWA, POP, IMAP, ActiveSync" -ForegroundColor green            
Set-CASMailbox -Identity $Alias -imapenabled $false -owaenabled $false `
-OWAforDevicesEnabled $false -popEnabled $false -ActiveSyncEnabled $false -PopUseProtocolDefaults $false -ImapUseProtocolDefaults $false            
Write-Host "OWA, POP, IMAP, ActiveSync disabled" -ForegroundColor green            
            
Sleep 10            
# Add the distributiongroup to the sharedmailbox with Full Access            
Write-Host "Setting Mailbox Full Access Permissions" -ForegroundColor green            
Add-MailboxPermission –Identity: $Alias –AccessRights:FullAccess –user:"SM.$Alias"
Write-Host "Full Access Permissions set" -ForegroundColor green

Sleep 10

# Add the distributiongroup to the sharedmailbox with Send-as
Write-Host "Setting Mailbox Send-as Permissions" -ForegroundColor green
Add-ADPermission –Identity "$Alias" –user "SM.$Alias" –ExtendedRights 'Send-as' -DomainController $DomainController            
Write-Host "Send-as Permissions set" -ForegroundColor green            
            
Sleep 10            
            
# Reset proxy to direct access            
netsh winhttp reset proxy            
Write-Host "Proxy Set to default" -ForegroundColor green            
Write-Host "Script Finished" -ForegroundColor green            
Write-Host "Close this window " -ForegroundColor Red            

15 May 2020

PowerShell behind a proxy - Annoying combination

Here is a list of all the methods I found to get PowerShell to work behind an authenticating proxy:

No 1:
$wc = New-Object System.Net.WebClient                        
$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials                        
$wc.DownloadString('http://microsoft.com')
No 2:
$proxy = New-Object System.Net.WebClient                        
$Proxy.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials                        
$webclient = New-Object System.Net.WebClient
No 3:
$creds = Get-Credential #Prompts for credentials                        
$webclient.Proxy.Credentials = $creds
No 4:
[System.Net.WebRequest]::DefaultWebProxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials            
[Net.ServicePointManager]::SecurityProtocol = "tls12"
No 5:
[system.net.webrequest]::defaultwebproxy = new-object system.net.webproxy('http://proxy.domain.lan:8080')                        
[system.net.webrequest]::defaultwebproxy.credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials                        
[system.net.webrequest]::defaultwebproxy.BypassProxyOnLocal = $true
No 6:
$browser = New-Object System.Net.WebClient            
$browser.Proxy.Credentials =[System.Net.CredentialCache]::DefaultNetworkCredentials
No 7:

Check current settings for the PowerShell session:
netsh winhttp show proxy

Output current WinHTTP proxy settings:
Direct access (no proxy server)

Set the proxy server:
netsh winhttp set proxy proxy.domain.lan:8080
Set the proxy server with bypass list:
netsh winhttp set proxy proxy-server="http=proxy.domain.lan;https=proxy.domain.lan:8080" bypass-list="*.domain.lan;10.*"
Check current WinHTTP proxy settings: Proxy Server(s) : proxy.domain.lan:8080 Bypass-List : (none)

Reset to no proxy server settings:
netsh winhttp reset proxy

Output reset WinHTTP proxy settings:
Direct access (no proxy server)

10 March 2020

All control panel commands to run from CMD prompt or PowerShell

Keep forgetting which commands to run for Control panel items?
Here's the list:

Command Name What does it do?
appwiz.cpl                   Uninstall or Change A Program
azman.msc                    Authorization Manager
bthprops.cpl                 Bluetooth & Other Devices
certlm.msc                   Certificate Manager for Local Computer
certmgr.msc                  Certificate Manager for Current User
comexp.msc                   Component Services, Event Viewer, Services 
compmgmt.msc                 Computer Management, System Tools, Storage and Services
desk.cpl                     Display layout
devmgmt.msc                  Device Manager 
DevModeRunAsUserConfig.msc   Start Menu Configuration
diskmgmt.msc                 Disk Management
eventvwr.msc                 Event Viewer
Firewall.cpl                 Firewall Manager
fsmgmt.msc                   Shared Folder Management
gpedit.msc                   Local GPO Editor
hdwwiz.cpl                   Device Manager (again!)
inetcpl.cpl                  Internet Properties
intl.cpl                     Region Settings
irprops.cpl                  InfraRed - on systems with IR
joy.cpl                      Game Controller
lusrmgr.msc                  Local User Manger
main.cpl                     Mouse Properties
mmsys.cpl                    Sound Properties
ncpa.cpl                     Network Interface properties
perfmon.msc                  Performance Monitor
powercfg.cpl                 Power Configuration
printmanagement.msc          Printer Manament
rsop.msc                     Resultant Set of Policy
secpol.msc                   Local Securityh Policy
services.msc                 Services
sysdm.cpl                    System Properties
TabletPC.cpl                 Tablet and Pen Settings
taskschd.msc                 Task Scheduler
telephon.cpl                 Phone Location Information
timedate.cpl                 Time and Date
tpm.msc                      Trusted Platform Module
WF.msc                       Defender Firewall
WmiMgmt.msc                  WMI Management
wscui.cpl                    Security and Maintenance

06 March 2020

Install PowerShell 7 with PowerShell Silently

Yesterday PowerShell 7 became GA, this means that I want to upgrade to this version the fastest way possible.
There's only one way to do this:
Invoke-WebRequest -Uri "https://github.com/PowerShell/PowerShell/releases/download/v7.0.3/PowerShell-7.0.3-win-x64.msi" -OutFile "$env:TEMP\PowerShell-7.0.3-win-x64.msi"

$msifile = "$env:TEMP\PowerShell-7.0.0-win-x64.msi"
$arguments = @(
          "/i"
          "`"$msiFile`""
          "/passive"
)
Start-Process -FilePath msiexec.exe -Wait -PassThru -ArgumentList $arguments
Or the preview version:

Invoke-WebRequest -Uri "https://github.com/PowerShell/PowerShell/releases/download/v7.1.0-preview.6/PowerShell-7.1.0-preview.6-win-x64.msi" -OutFile "$env:TEMP\PowerShell-7.1.0-preview.6-win-x64.msi"
$msifile = "$env:TEMP\PowerShell-7.1.0-preview.6-win-x64.msi"
$arguments = @( "/i" "`"$msiFile`"" "/passive" ) Start-Process -FilePath msiexec.exe -Wait -PassThru -ArgumentList $arguments
Keep in mind that with PowerShell 7 the ISE is no longer available, and you need to shift to VisualStudio Code.
https://code.visualstudio.com/

Or with this oneliner:
iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI"

Roll Over Kerberos Decryption Key - Untill the uservoice feature gets implemented

Every 30 days your are required by Microsoft to "rollover" the Pass-throug Authentication Kerberos key for your tenant.
In the near future you don’t need to perform any Powershell or scripting referring to Microsoft user voice “We are currently working on an approach that will allow Tenant Admins to do key rollover from the Azure AD portal; without the need for PowerShell or scripting”

But until then we do this:

On your AzureADConnect machine go to:
PS C:\> cd '.\Program Files\Microsoft Azure Active Directory Connect'
Then import:
PS C:\Program Files\Microsoft Azure Active Directory Connect> Import-Module .\AzureADSSO.psd1

Run the commandlet New-AzureADSSOAuthenticationContext:
PS C:\Program Files\Microsoft Azure Active Directory Connect> New-AzureADSSOAuthenticationContext
Check the current status:
PS C:\Program Files\Microsoft Azure Active Directory Connect> Get-AzureADSSOStatus
{"Enable":true,"Exists":true,"Domains":["domain.lan"],"IsSuccessful":true,"ErrorMessage":""}
Then enter your on-premises domain administrator credentials:
PS C:\Program Files\Microsoft Azure Active Directory Connect> $creds = Get-Credential
Then run the command to rollover the key's Update-AzureADSSOForest -OnPremCredentials $creds:
PS C:\Program Files\Microsoft Azure Active Directory Connect> Update-AzureADSSOForest -OnPremCredentials $creds
The output should look like this:
[12:10:32.685] [  5] [INFORMATIONAL] UpdateComputerAccount: Locating SSO computer account in DOMAIN...
[12:10:32.701] [  5] [INFORMATIONAL] GetDesktopSsoComputerAccount: Searching in global catalog(forest) and DOMAIN for co
mputer account AZUREADSSOACC
[12:10:33.232] [  5] [INFORMATIONAL] TrySearchAccountUnderGlobalCatalog: Object was found in global catalog(forest), hen
ce skipping DOMAIN search
[12:10:33.232] [  5] [INFORMATIONAL] UpdateComputerAccount: Found SSO computer account at CN=AZUREADSSOACC,CN=Computers,
DC=domain,DC=lan. Updating its properties...
[12:10:33.232] [  5] [INFORMATIONAL] UpdateComputerAccount: Granting full control to account admins and enterprise admin
s for computer account CN=AZUREADSSOACC,CN=Computers,DC=domain,DC=lan...
[12:10:33.907] [  5] [INFORMATIONAL] UpdateComputerAccount: Successfully updated SSO computer account properties.
The operation completed successfully
PS C:\Program Files\Microsoft Azure Active Directory Connect>

04 February 2020

Microsoft Store is blocked - 0x800704EC

Image result for microsoft store is blocked

Well isn't this lovely.
But there's away around this.

In the registry go to:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PolicyManager\default\ApplicationManagement\AllowStore

And change "DoNotAllow" from 1 to 0.
Voila.