Category Archives: Powershell

VMware and Powershell

Broadcom the owner and vendor of VMWare have release a new powershell module, called VCF.PowerCLI instead of the vmware PowerCLI.
If you computer is online, you can installed it with the powershell command Install-Module

Install-Module -Name VCF.PowerCLI

If yours computer/server is not online, you can download it from another computer, and installed it though the manuel way, please look here: https://developer.broadcom.com/powercli/installation-guide

When upgradering from Vmware PowerCLI – Throubleshooting
If you allready have Vmware PowerCLI installed on the computer, you may encounter the following error when trying to install VCF.PowerCLI

PackageManagement\Install-Package : The following commands are already available on this system

This happens because some of the commandlets which are part of the PowerCLI SDK have been moved to other modules. To resolve the conflict you need to add the AllowClobber parameter to Install-Module

Install-Module -Name VCF.PowerCLI -AllowClobber

AllowClobber overrides warning messages about installation conflicts about existing commands on a computer. Overwrites existing commands that have the same name as commands being installed by a module. AllowClobber and Force can be used together in an Install-Module command.

Problems in connection to a Webservice from Windows Server 2016 / 2019

Today, I have this issue, that i could not connect to a webservices, that are hosted by the Danish Tax Service, the URL where: https://emcstest.skat.dk
I got this warning:

Invoke-WebRequest : The request was aborted: Could not create SSL/TLS secure channel.

When running these commands

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$WebResponse = Invoke-WebRequest "https://emcstest.skat.dk"

No matter what I did. But final I tested the webpage against SSLLabs
https://www.ssllabs.com/ssltest/analyze.html?d=emcstest.skat.dk
Found these ciphers

I then run these commands:

Enable-TlsCipherSuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
Enable-TlsCipherSuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
Enable-TlsCipherSuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
Enable-TlsCipherSuite TLS_AES_256_GCM_SHA384
Enable-TlsCipherSuite TLS_AES_128_GCM_SHA256
Enable-TlsCipherSuite TLS_CHACHA20_POLY1305_SHA256
Enable-TlsCipherSuite TLS_AES_256_GCM_SHA384

And finally I where able to access the webpage though powershell.

Get Certificate from remote computers

If you need to get all certificates, from a list of remote computers, you can use this script:

$Servers = "kennethdalbjerg-dc01",
           "kennethdalbjerg-dc02",
           "kennethdalbjerg-exch01",
           "kennethdalbjerg-fs01"
 
  $Results = @()
  $Results = Invoke-Command -cn $Servers {
          $Certs = @{} | Select Certificate,Expired
          $Cert = Get-ChildItem Cert:\LocalMachine\My
          If($Cert){
              $Certs.Certificate = $Cert.subject
              $Certs.Expired = $Cert.NotAfter
          }
          Else{
              $Certs.Certificate = " - "
              $Certs.Expired = " - "
          }
          $Certs
  } | Select-Object @{n='ServerName';e={$_.pscomputername}},Certificate,Expired
 
  #Display results in console
  $Results | Sort-Object Expired -Descending
 
  #Save results to CSV file
  $Results | Sort-Object Expired -Descending | Export-Csv -Path C:\users\$env:username\desktop\cert_results.csv -NoTypeInformation -Force
 
  #Open results in new window
  $Results | Sort-Object Expired -Descending | Out-GridView -Title "Final results"

Found groups that a 365 contacts is member of

If you need to found out whitch groups (mailling groups) a contact is member of in Microsoft 365, then you case use these powershell commands:

$getsessions = Get-PSSession | Select-Object -Property State, Name
$isconnected = (@($getsessions) -like '@{State=Opened; Name=ExchangeOnlineInternalSession*').Count -gt 0
If ($isconnected -ne "True") {
Connect-ExchangeOnline
}

$dn = (Get-MailContact "[email protected]").DistinguishedName
Get-Recipient -Filter "Members -eq '$dn'"

Replace [email protected] with yours mail address.

Passler PRTG Windows update Probe says missing updates, but none in windows update

You can run this commands to see what updates, that PRTG windows update probes is warning about.

$searcher = (New-Object -ComObject Microsoft.Update.Session).CreateUpdateSearcher();$searcher.Search("Type='Software'").Updates | Sort-Object -Property Dates -Descending | ft -autosize IsInstalled, MsrcSeverity,title

Installation of New Exchange server

If you ever have installed a new Exchange server in an Active Directory orgainisation that allready have an Exchange server (That’s not so often anymore), you may have discovered that users get Certificate warning in Outlook, unto you have changed the URL’s to match the certificates.

But I found this script on Github: https://gist.github.com/kevinblumenfeld/31b03bf439b1f94f460eb754ef74120e

It copy the settings of all IIS url’s to the new Exchange server, when it found it in Active Directory.
So run this script before the start of the installation, and you will not receive the certificate warnings after the installation.

Compare two folders with Powershell

This script checks first that folders exist, then that filename are the same, and then that file Hash is the same

#$folder1 = "C:\Temp\test"
#$folder2 = "C:\Temp\test2"


if ((Test-Path -Path $folder1) -and (Test-Path -Path $folder2)) {
    echo "The folders exist"
    echo "Folder1: $folder1"
    echo "Folder2: $folder2"
    $sourceFiles = Get-ChildItem $folder1 -Recurse
    $destFiles = Get-ChildItem $folder2 -Recurse
    if (Compare-Object $sourceFiles.Name $destFiles.Name) {
        echo "The folders is not the same"
    } else {
        echo "Check of the folders show us that there have the same content - OK"
        $SourceDocs = Get-ChildItem –Path $folder1 -Recurse | foreach  {Get-FileHash –Path $_.FullName}
        $DestDocs = Get-ChildItem –Path $folder2 -Recurse | foreach  {Get-FileHash –Path $_.FullName}
        if ($SourceDocs.Hash -ne $destDocs.Hash) {
            echo "There are difference in the the files"
            echo "folder1 Hash: $SourceDocs.hash"
            echo "folder2 Hash: $DestDocs.hash"
        } else  {
            echo "The folders are the same!"
        }
    }
} else {
    Echo "One of the folders or both, dosn't exist"
}

Add Exchange management Shell to “normal powershell

Here are a script, that you can include in yours script, to add Exchange management shell, to “normal” powershell scripts.

$StopWatch = [System.Diagnostics.StopWatch]::StartNew()
Function Test-Command ($Command)
{
    Try
    {
        Get-command $command -ErrorAction Stop
        Return $True
    }
    Catch [System.SystemException]
    {
        Return $False
    }
}

IF (Test-Command "Get-Mailbox") {Write-Host "Exchange cmdlets already present"}
Else {

    $CallEMS = ". '$env:ExchangeInstallPath\bin\RemoteExchange.ps1'; Connect-ExchangeServer -auto -ClientApplication:ManagementShell "

    Invoke-Expression $CallEMS
$stopwatch.Stop()
$msg = "`n`nThe script took $([math]::round($($StopWatch.Elapsed.TotalSeconds),2)) seconds to execute..."
Write-Host $msg
$msg = $null
$StopWatch = $null
}

Remote Desktop seesions – See sessions on all servers in Active directory

If you have enabled that a user get lock out in Active Directory, if the user type the password wrong X times.
Then you might have experienced, that yours admin account get locked out multiple times, just after you have change the password for the admin account.

It could be that you have left a session on a server in you Active Directory logged on, and that session now trying to authenticated it self, by using you old password.

You can run this script, to check all servers in Active Directory, to see where there are user session on it.

function Get-LoggedOnUsers ($server) {
    if($server -eq $null){
        $server = "localhost"
    }
 
    $users = @()
    # Query using quser, 2>$null to hide "No users exists...", then skip to the next server
    $quser = quser /server:$server 2>$null
    if(!($quser)){
        Continue
    }
 
    #Remove column headers
    $quser = $quser[1..$($quser.Count)]
    foreach($user in $quser){
        $usersObj = [PSCustomObject]@{Server=$null;Username=$null;SessionName=$null;SessionId=$Null;SessionState=$null;LogonTime=$null;IdleTime=$null}
        $quserData = $user -split "\s+"
 
        #We have to splice the array if the session is disconnected (as the SESSIONNAME column quserData[2] is empty)
        if(($user | select-string "Disc") -ne $null){
            #User is disconnected
            $quserData = ($quserData[0..1],"null",$quserData[2..($quserData.Length -1)]) -split "\s+"
        }
 
        # Server
        $usersObj.Server = $server
        # Username
        $usersObj.Username = $quserData[1]
        # SessionName
        $usersObj.SessionName = $quserData[2]
        # SessionID
        $usersObj.SessionID = $quserData[3]
        # SessionState
        $usersObj.SessionState = $quserData[4]
        # IdleTime
        $quserData[5] = $quserData[5] -replace "\+",":" -replace "\.","0:0" -replace "Disc","0:0"
        if($quserData[5] -like "*:*"){
            $usersObj.IdleTime = [timespan]"$($quserData[5])"
        }elseif($quserData[5] -eq "." -or $quserData[5] -eq "none"){
            $usersObj.idleTime = [timespan]"0:0"
        }else{
            $usersObj.IdleTime = [timespan]"0:$($quserData[5])"
        }
        # LogonTime
        $usersObj.LogonTime = (Get-Date "$($quserData[6]) $($quserData[7]) $($quserData[8] )")
 
        $users += $usersObj
    }
    return $users
}

$strCategory = "computer" 
$strOperatingSystem = "Windows*Server*" 
 
$objDomain = New-Object System.DirectoryServices.DirectoryEntry 
 
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher 
$objSearcher.SearchRoot = $objDomain 

$objSearcher.Filter = ("OperatingSystem=$strOperatingSystem") 
 
$colProplist = "name" 

foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)} 

$colResults = $objSearcher.FindAll() 

foreach ($objResult in $colResults) 
    { 
    If ($Err -ne $null) {
        Remove-Variable Err
    }
    $objComputer = $objResult.Properties;  
    $ServerName = $objComputer.name
    $isalive = Test-Connection -BufferSize 32 -Count 1 -ComputerName $servername -Quiet
    if($isalive -eq $True) {
        $wmi = Get-WmiObject -class "Win32_Process" -namespace "root\cimv2" -computername $ServerName -EV Err -EA SilentlyContinue
        if ($Err) {
         } Else {
            Get-LoggedOnUsers $ServerName | ft -autosize
        }

    }
}

 

 

You can change this last command:

Get-LoggedOnUsers $ServerName | ft -autosize

to

Get-LoggedOnUsers $ServerName | ? { $_.Username -eq ‘kda’ } | ft -autosize

to only see where KDA is loggedon