måndag 9 december 2013

CRL/OCSP cache Control


Once again the Process Monitor solved the case. This time I had a case when I was implementing an online responder at a customer site. When we did some initial testing the responder cluster seemed to give up after few hundred queries. The solution we had planned demanded a high available responder and very high performance. The customer site had no way of reaching the published CRL's in the certificate CDP. This is why we chose to install an onsite online responder to serve locally. All clients and servers got the responder setting specified through gpo's


By using this PS-script I was able to do thousands unique queries to the OCSP. The script rely on certificate files residing in a local folder.


The result was always the same. When the cache entries value exceeded 500 from the same CA the client stopped query the OCSP.






The GPO-setting specifying the amount of queries the client should do before switching to CRL did not give any response. It did not change the behavior at all.
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\ChainEngine\Config
CryptnetCachedOcspSwitchToCrlCount


I did contact MS-support for some assistance in this case and they really could not help. Then I got the idea to try 'Process Monitor' to see what really happened. Right away the application showed me that that it tried to read a registry key that was missing.

   


HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CertDllCreateCertificateChainEngine\Config\
CryptnetMaxCachedOcspPerCrlCount
This value seemed pretty exactly what I was looking for, but undocumented. Trying to regulate the behavior of the crl-cache by creating this key and setting its value to 2000 I could run my tests without any errors. Now we can use the responder without any problem.


Once more I did contact Microsoft Support for an official statement about using the value. This is their response.
"As indicated by these default values, we recommend the use of a single CRL instead of thousands of OCSP responses. Each chain build will require an online network retrieval. These individual OCSPs will be cached in the login process and file system. Assuming 2K per OCSP response this would be 2M bytes per 1K users.
You are probably OK using OCSP if the number of users is under 10K. "

måndag 26 augusti 2013

Gamla profiler.

När en användare i Active Directory raderas kan dess profil finnas kvar på alla servrar som kontot har loggats in på. Jag vart nyfiken på hur mycke data som låg kvar ute på servarna i nätet. Dessa funktioner letar igenom Windows 2008 servrar efter lokala profiler vars konton är inaktiva eller okända.

Skriptet består av fyra funktioner. Alla funktionerna använder pipen för input.

Exempel.

Körs frFör att kolla alla servrar vars namn börjar på 'SRV0*'
Get-ADComputer -Filter {name -like "SRV0*"} | Find-UserProfiles | Translate-SidToUserName | Check-User


Lycka till




---- Skript ----

import-module activedirectory

Function Test-PortConnection
{  
    param([string]$sName)
    try
    {
        $ret = ([Net.DNS]::GetHostAddresses($sName))[0].IPAddressToString
        $tcpClient = New-Object System.Net.Sockets.TCPClient
        $tcpClient.Connect("$ret",135)
        $tcpClient.Connected
    }
    catch [System.Net.Sockets.SocketException]
    {
       Write-host " - " + $_.Exception.message -ForegroundColor red
       $false
    }
    catch
    {
    }
}
Function Find-UserProfiles
{
    Process
    {
        try
        {
            write-host $_.name -ForegroundColor Green -nonewline
            if (Test-PortConnection ($_.name))
            {
                Get-WmiObject Win32_UserProfile -ComputerName ($_.name) -ea Stop | Select sid, lastusetime 
                write-host . -ForegroundColor Green
            }   
        }
        Catch [System.Runtime.InteropServices.COMException]
        {
            Write-host " Blockerad "  -ForegroundColor Red
           
        }
         catch
        {
        write-host "Undantagsfel: $_.Exception.GetType()"
        }
    }
}
Function Translate-SidToUserName
{
    Process
    {
        $oSID = New-Object System.Security.Principal.SecurityIdentifier($_.sid)
        if($osid.IsAccountSid())
        {
      
            try
            {
                if($_.lastusetime -ne $null)
                {
                    $Time = ([WMI] '').ConvertToDateTime($_.lastusetime)
                    $Days = (New-TimeSpan -Start $time -End (get-date)).days
                }
                Else
                {
                    $days = 0
                }
                $osid = $oSID.Translate([System.Security.Principal.NTAccount])
                Add-Member -InputObject $oSID -MemberType noteproperty -Name "LastUse" -Value $days -PassThru
               
            }
            catch [System.Management.Automation.MethodException]
            {
                   if ($osid.IsEqualDomainSid((Get-ADDomain).domainsid.tostring())) {Write-host "`n  $oSID `t $days"}
            }
            catch
            {
            " Undantagsfel: " + $_.Exception.GetType()
            }
        }
    }
   
}
function Check-User
{
    Process
    {
        if($_.value.length -gt 1 -and $_ -notmatch "NT AUTHORITY")
        {
            $dom = ($_.value).split("\")[0]
            $usr = ($_.value).split("\")[1]
            if($dom -notLike ($env:computername))
            {
                $sOut = $usr | get-aduser -Properties enabled |where {$_.enabled -eq $false}
                if($sOut){Add-Member -InputObject $sOut -MemberType noteproperty -Name "LastUse" -Value ($_.lastuse) -force }
               
                $sout | FT Name, lastuse -AutoSize -HideTableHeaders
            }
        }
    }
}


tisdag 31 juli 2012

Återställa rättigheter på kataloger eller filer.

Återställa rättigheter på en katalog. Med hjälp av 'export-clixml" är de enkelt att spara undan objekt. De kan vara användbart många gånger att kunna återskapa kopior av objekten.

Exemplet nedan är ett sätt att återställa rättigheterna på en katalog.
1. Sätt ACL:n på katalogen eller filen som du vill ha den.

2. Skapa ACL-Objektet  och spara de till en fil.
$tmp = get-acl c:\thefolder
$tmp | Export-Clixml .\aclobj.csv

3. Återställ katalogen genom att läsa in objektet och sätt acl:en på katalogen.
$oAcl = .\aclobj.csv
set-acl -Path c:\thefolder -AclObject $oAcl

tisdag 29 maj 2012

Felhantering i powershell

Felhantering i Powershell med Try and Catch är relativt enkelt. Jag hade däremot lite mer besvär att hitta namnet på de undantagsfel som som kastats.

Här är ett exempel hur du hittar namnen.

import-module activedirectory
try
    {new-aduser jimmy}
Catch
    {write-host "Okänt fel"
    write-host "Fel text: " $_
    write-host "Undantagsfel: " $_.Exception.GetType()}
Detta svar får jag:
Okänt fel
Fel text:  The specified account already exists
Undantagsfel:  Microsoft.ActiveDirectory.Management.ADIdentityAlreadyExistsException

Med hjälp av denna strängen kan jag hantera detta i koden. Notera den nya sektionen i blått som hanterar ett känt fel.


try
    { new-aduser jimmy }
Catch [Microsoft.ActiveDirectory.Management.ADIdentityAlreadyExistsException]
  { write-host "Användaren finns redan."  }
Catch
    { write-host "Okänt fel"
    write-host "Fel text: " $_
    write-host "Undantagsfel: " $_.Exception.GetType()}

Smidigt och enkelt!

onsdag 23 maj 2012

Skapa användare i AD från en CSV-fil med Powershell.

Importera användare till Active Directory från en csv-fil med hjälp av Powershell kan vara väldigt enkelt men några vanliga fällor kan dyka upp. Här är några av mina lösningar.

 CSV-filen
· Formatet på infilen, dessa verkar alltid vara olika. I vissa fall kan de lösas med delimiter parametern på import-csv (finns från och med version 2 av Powershell)
exempel : 
import-csv .\test.csv -Delimiter ";"
· Ett annat fel som jag stött på är om första raden (kolumnhuvuden) avslutas med ett skiljetecken. Detta verkar inte Powershell inte kunna hantera.
Exempel:
Name;ålder;längd;
Jim;42;185
Radera semikolonet efter längd så kommer de fungera.
·  Teckenformatet klara inte åäö i datat. En lösning på detta problemet är att köra "get-content" och skicka de till en ny fil.
Exempel:
get-content .\test.csv > .\test_fixed.csv
Lösenordet.
 Se till att de lösenordet du försöker sätta följer lösenordspolicyn i domänen. De går inte att skicka med lösenordet som en sträng i klartext. Här är två exempel på hur du kan göra.
· Om lösenordet ska vara enligt ett fält från csv-filen måste de konverteras till ett System.Security.SecureString-format.  I detta exempel är lösenordet sparat i "Password" kolumnen vilket inte kommer fungera utan att byta namn på parametern enligt exempel i nästa sektion.
import-csv .\test.csv -Delimiter ";" |
% {$_.password = $_.password |
ConvertTo-SecureString -AsPlainText -Force;$_}
· Om de är en större mängd konton som ska skapas med samma lösenord, skapa variablen först exempel:
$UsrPwd = convertto-securestring "Password-1" -asplaintext -force
Variabeln kan sen användas med New-ADUser cmdlet.
Exempel:
New-ADUser -Name "Jimmy" -AccountPassword $UsrPwd

Parameternamnen ska matcha kolumnhuvuden.
Snyggast är de när objektet som kommer i pipen mappar sina attribut direkt till rätt parametrar. För att få rätt kolumn till rätt parameter kan de krävas att namnen ändras. Om de är en engångsföreteelse är de nog enklast att byta kolumnnamn i csv-filen. I andra fall kan powershell mappa om parametrar med  Select-object cmdlet. Exempelet nedan mappar om 'Efternamn' till 'Surname' och 'Password' till 'AccountPassword'.  

 
Import-Csv -Path $sPath -Delimiter ";"| Select @{Name="Surname";Expression={$_."Efternamn"}}, @{Name="AccountPassword";Expression={$_."Password"}} | New-ADUser
I vissa fall kan man behöva lägga till flera attribut direkt i pipen med data som inte kommer från csv-filen. Exempel:

Import-Csv -Path $sPath -Delimiter ";" | Add-Member -name AccountPassword -type noteproperty -value $Password –PassThru | New-ADUser


onsdag 16 maj 2012

Inventera katalogstrukturer efter grupp/användar-rättigheter.

En kollega till mig behövde hitta alla delade kataloger som en specifik grupp hade rättigheter till. Jag skrev detta skript som letar igenom filstrukturer och visar vart gruppen har rättigheter.

För att skriptet ska fungerar krävs ett infil med vilka kataloger som ska sökas igenom.

Uppdatera $FileShares variabeln till vart du har din fil med kataloger som ska sökas igenom.
Uppdatera $Grp variabeln till vilken grupp du söker efter.

Lycka till. 

--- Exempel: share.txt ----

\\fileserver1\homefolders
\\fileserver2\groupfolders



---- Skript: GrpSearch.ps1  ----

<#
  Titel: GrpSearch.ps1
  Beskrivning: Söker efter rättigheter på kataloger.
 Av: Jimmy Benandex

#>


# Uppdatera dessa variabler.
$FileShares = "C:\temp\shares.txt"
$Grp = "LAB\Domain Users"

function Check-missing ($acl) {
    $users = $acl.Access | select IdentityReference -Unique
    $ac = $users | % {$_.IdentityReference.value}
 if ($ac -contains $Grp ) {$acl.psPath | Convert-path}
 }

Function Check-Folder ($fol){
 Process {
  check-missing $_
  $sPath = $_.psPath | Convert-path
  dir $sPath | Where {$_.psIsContainer -eq $true} |
        foreach {get-acl $_.pspath | Check-Folder}
  }
 }

gc $FileShares | % {
 $tmp = Get-Acl $_
 $tmp | Check-Folder
 }

tisdag 15 maj 2012

Vilka parametrar är tvingande på en cmdlet?

En bra oneliner för att få fram vilka parametrar som är tvingande på en cmdlet. Exemplet nedan är på New-ADUser cmdlet:en som finns i ActiveDirectory modulen som tydligen bara har en tvingande parameter.

(get-help new-aduser).parameters.parameter | where {$_.Required -eq $true}

Lycka till