Home » 2014 » October

Monthly Archives: October 2014

Force Removal of McAfee Enterprise 8.x

To forcefully remove McAfee Enterprise Virus Scan 8 you can use msiexec for the removal


msiexec /x {CE15D1B6-19B6-4D4D-8F43-CF5D2C3356FF} REMOVE=ALL REBOOT=R /q


This will quickly remove mcafee for an alternative AV product install

Creating a Receive Connector for TLS (Encrypted) E-mail Exchange 2013

Email transmissions between companies sometimes need to be encrypted in transit. In order for this encryption to work across links both exchange servers must have a valid and trusted SSL certificate. If using Internal CA certificates, both exchange servers must have the each others Root CA cert and any Intermediates installed locally in the relevant certificate stores, and must be able to lookup the certificate revocation list of the certificate. Therefore each network myst have a CRL publishing point available to each other.

To create a Receive Connector to accept TLS encrypted email you must first declare the remote email domain in the TlsReceiveDomainSecureList of exchange 2013. This is done using the Set-TransportConfig exchange management shell command

Set-TransportConfig -TLSReceiveDomainSecureList @{Add="remotedomain.com"}

Now to create the receive connector

New-ReceiveConnector -Name TLSReceive -Usage Custom -Bindings "" -TransportRole "FrontEndTransport" -AuthMechanism TLS -DomainSecureEnabled $true -Fqdn "tlsmail.domain.com" -RequireTLS $true -TlsCertificateName [s]subject name

To get the subject name of the certificate use the Get-ExchangeCertificate cmdlet.

How to Pass variables from local PS Session to Remote PS Session

When writing scripts for admin tasks I wanted to explore the idea of running scripts locally on a management workstation rather than RDP to each server and run a command. The Invoke-Command can achieve this nicely. However, what if I wanted to pass a declared variable from my management workstation to the remote PS Session?

e.g. $Ping = “www.google.co.uk”

This is set on my management workstation Powershell session. But I want to test I can ping this from another server or web address. In order to do this we need to declare the variable $Ping in our Invoke-Command -Scriptblock  and -ArgumentList parameters.

Invoke-Command -Session $PSSessionName -ArgumentList -Scriptblock {
Test-Connection -Computername $Ping

This will output

Source        Destination     IPV4Address      IPV6Address                              Bytes    Time(ms)  PSComputerName
——        ———–     ———–      ———–                              —–    ——–  ————–
WIN-83AIC7… http://www.google.c…                                             32       38        WIN-83AIC7KIGI1.test.domain
WIN-83AIC7… http://www.google.c…                                             32       42        WIN-83AIC7KIGI1.test.domain
WIN-83AIC7… http://www.google.c…                                             32       36        WIN-83AIC7KIGI1.test.domain
WIN-83AIC7… http://www.google.c…                                             32       36        WIN-83AIC7KIGI1.test.domain

If you are using Powershell 3.0 you can use the $using scope modifier instead of declaring Parameters or Argumentlists like so

Invoke-Command -Session $PSSessionName -Scriptblock {
Test-Connection -Computername $using:Path



Enable Powershell Sessions to Domain Joined server from Workgrouped Machine

To create Powershell sessions to domain joined machines from a service workstation that is workgrouped joined you need to perform the following actions on the workgrouped machine

1) Start the WS-Management Service

2) Open Command Prompt and enter the following command

winrm s winrm/config/client '@{TrustedHosts="server.domain.local"}'

Assuming the target server is remote management enabled this will allow you to create PS Sessions with the New-PSSession Cmdlet

To enable remote management on the target machine if required, enter the following powershell command

Enable-PSRemoting -Force


Removing Soft Deleted Mailboxes from Exchange

When performing mailbox moves sometimes they complete with warnings. When you interrogate the move log you may find that the move was successful but the request failed to clean up the source database.

Microsoft say they resolved this in Microsoft Exchange 2010 SP3 but I have seen this happen in later releases SP3 CU5 and 2013.

To manually remove these disconnected mailboxes you need to use EMS. First find the disconnected mailbox in the source database

Get-MailboxStatistics -Database <source database name> | Where { $_.DisconnectReason -eq "SoftDeleted" } | fl DisplayName, MailboxGUID

Then use the following command to remove them

Remove-StoreMailbox –Database <source database name> –Identity <user mailbox GUID> –MailboxState Softdeleted

You will need to wait for the maintenance routine to run on the database before the white space is reclaimed

Forcing SSL Certificate to Associate with Server’s Private Key

Have you ever been handed a certificate exported (without the private key) from a server or directly from a CA to install on a different server than the one used to create the CSR? Whilst some IIS functions and apps allow you to use a certificate without a private key, there are others that demand it. In any case best practice is to import a certificate with the private key used to create the CSR in the first place. However, there are circumstances where this may not be possible. Perhaps the admin who installed the certificate on the original server forgot (or intentionally) to mark the private key as exportable. Perhaps this is not the first export of the certificate and the private key has got lost. In these events using these certificates without the proper private key can prevent applications and web services functioning. Classic examples are Lync and UM for Exchange.

Fortunately, there is a way to resolve this issue without purchasing a new certificate.

First we need to get the serial number of the certificate. If your certificate is not yet imported, please import this now. You can use the Certificate MMC Snap-in or if PFX file you can double click and install it. To get the serial number of the certificate either open the certificate and browse the details tab for the serial number or run this PowerShell command

Get-ChildItem -Path cert:\LocalMachine\my | Select-Object Subject,Serialnumber

Replace the Path with the correct one you installed the certificate. the above command uses the local machine personal store, which is usually the place certificates get installed.

This command will produce a similar output to this

Subject                                                     SerialNumber
-------                                                     ------------
CN=localhost                                                4CA2A1EF3CF850B24A6F8841382950AC
E=admin@goldenfrog.com, CN=goldenfrog-client, O=GoldenFr... 1A
E=admin@goldenfrog.com, CN=GoldenFrog-Inc CA, O=GoldenFr... 00D776530B7B49A6EC

Copy the serial number of the certificate you want to edit from the table

Next we need to associate forcefully the private key of the server to the certificate we have imported.

Open Command Prompt as an administrator and type on the following command

certutil.exe -repairstore my <serial number of cert>

And Magic the certificate is now associated with the server’s private key

Auditing Installed Applications on Server or PC using Powershell

Here is a simple Powershell function to audit installed apps on local or remote machine using PowerShell. The script queries the registry for installed apps rather than using Get-WMIObject as this would rerun any msi installer packages and attempt a repair (an annoying side effect). The impact of the Get-WMIObject method would mean any custom changes to the MSI i.e manual service stop or desktop shortcut would be reversed. Using the registry is a lot safer and quicker. The account used to run this script must have local administrator access and the target machine should have remote management and remote registry enabled.

to run the script use the Get-InstalledSoftware commandlet without specifying anything this will audit the local machine. Specifying the -Computername parameter targets a remote machine. Reports are HTML reports that will be written to c:\Reports on the machine this script is executed from.

Script below

Function Get-InstalledSoftware(){ 
 Param (
 $a = "<style>"
 $a = $a + "BODY{background-color:peachpuff;}"
 $a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
 $a = $a + "TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:thistle}"
 $a = $a + "TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:PaleGoldenrod}"
 $a = $a + "</style><title>Installed Applications</tif folditle>"
if (!(Test-Path -Path "C:\Reports")){
 $logFolder = New-Item -Path "C:\Reports" -ItemType Directory
 $logFolder = "C:\Reports"
 if (!$ComputerName ){
 Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object {$_.DisplayName} |`
 Select-Object DisplayName, Publisher, DisplayVersion, InstallDate | ConvertTo-Html -Head $a `
 -Body "<h1>Installed Applications</h1>" -As List | Out-File "$($logFolder)\installedapps.htm"
$query = Invoke-Command -ComputerName $ComputerName -ScriptBlock { Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall |`
 Get-ItemProperty | Where-Object {$_.DisplayName} |`
 Select-Object DisplayName, Publisher, DisplayVersion, InstallDate}
 $query | ConvertTo-Html -Head $a `
 -Body "<h1>Installed Applications on: $ComputerName</h1>" -as List | Out-File "$($logFolder)\$($ComputerName)_installedapps.htm"

Copy users from on Active Directory to another (no trust/ADMT)

I had a scenario whereby a customer wanted to migrate from SBS2003 to Server 2012 and Exchange 2013 in one hop. There was not enough resources to install and exchange 2010 migration server to move mailboxes over EWS and due to SBS constraints we cannot use ADMT to migrate as Domain Trusts cannot be made between SBS and any other domain. The solution we opted for was to build a new domain with exchange 2013 installed and then migrate the users over using a mixture of export scripts from the SBS domain and PST files for their email.

As we were migrating to an independent domain we don’t really need to worry about SID History as we are not accessing resources in the old domain after migration. What we do need to worry about is the X500 address of the user. I have another blog post about the importance of this attribute when moving between exchange servers on different domains.

First I exported all the users from the old domain using CSVDE, because AD Powershell was not available on SBS2003

CSVDE -f c:\users.csv -d “OU=users,OU=SBS Company,DC=domain,DC=local” – r (objectClass=user)

This produced the required CSV with all the attributes we need and more!

I then copied this file to the new domain and created a powershell script to read through these users, enable their mailboxes (if required) and add them to or create and add them to security groups they were members of in the old domain. In order to achieve this the script reads the memberOf field of the user and splits the groups into an array. It then checks the groups exists in new domain. if it does it will add the user to the group. If it doesn’t it will create the group and add the user to it. There is a limitation in using this script in this way. It will not discriminate between distribution or security groups. What I mean is that when it creates a group it will be a security group regardless whether the group was a distribution group in the old domain. But this was OK for me to do it this way.

The script allows you to add the destination location of the users and groups OU as well as choosing whether to enable a mailbox or not. If you choose to enable a mailbox then you must supply the PowerShell URL of the exchange server e.g http://exchangeserver.domain.com/powershell

Log files are written to C:\ADMigration folder which will be created. During the user import, a random password will be generated for the user. These passwords are stored in a folder called userpasswords.txt located in C:\ADMigration folder.


Ensure Exchange is installed before running this script if you are migrating mailboxes, otherwise it will create the exchange groups and may cause issues

Turn off Password history and complexity requirements temporarily in the domain as I have had weird issues with this script when it is enabled


Here is the script, copy this into notepad or PS ISE and save with the ps1 extension



Random Password Function Powershell

To generate a random password for Active directory you can use this function

Function Get-RandomPassword(){
Param (
$alphabet=$NULL;For ($a=65;$a –le 90;$a++) {$alphabet+=,[char][byte]$a }
$ascii=$NULL;For ($a=33;$a –le 126;$a++) {$ascii+=,[char][byte]$a }
For ($l=1; $l -le $length; $l++){ 
 $tempPassword += ($alphabet | Get-Random)
 $tempPassword += ($ascii | Get-Random)
return $tempPassword


Even though the length is 5, it will actually produce a 10 character password because it will use UPPERCASE letters x 5 and ASCII characters x 5

Add Users Home Folder and Set Permissions Powershell

By now most admins are Ok creating new user accounts in Active Directory. However, one thing the New-ADUser commandlet does not do is create a home folder for the user. The preferred way by me is always let group policy handle this but on occasions companies still use active directory for home folders.

Here is the script to create a home folder on the home shared drive and set the correct permissions

 $NewFolder = New-Item -Path "\\serverfqdn\userhome" -Name <username> -ItemType "Directory"
 $Rights = [System.Security.AccessControl.FileSystemRights]"FullControl,Modify,ReadAndExecute,ListDirectory,Read,Write"
 $InheritanceFlag = @([System.Security.AccessControl.InheritanceFlags]::ContainerInherit,[System.Security.AccessControl.InheritanceFlags]::ObjectInherit)
 $PropagationFlag = [System.Security.AccessControl.PropagationFlags]::None
 $objType =[System.Security.AccessControl.AccessControlType]::Allow
 $objUser = New-Object System.Security.Principal.NTAccount "<domain>\<username>"
 $objACE = New-Object System.Security.AccessControl.FileSystemAccessRule ($objUser, $Rights, $InheritanceFlag, $PropagationFlag, $objType)
 $ACL = Get-Acl -Path $NewFolder
 Set-ACL -Path $NewFolder.FullName -AclObject $ACL
%d bloggers like this: