All posts by steven

Convert String to Scriptblock Function

You cannot invoke-command a string. You should use a Scriptblock. If you import a value as a string you can convert it only if it is a single value string using the following command:

[scriptblock]::Create("$string")

To convert an multivalue array to scriptblock you can use a module as shown below:

function Convert-StringToScriptBlock {
param(
[parameter(ValueFromPipeline=$true,Position=0)]
[string]
$string
)
$sb = [scriptblock]::Create($string)
return $sb
}

Export-ModuleMember -Function 'Convert-StringToScriptBlock'

ZIP:

Convert-StringtoScripblock

Import PFX Certificate Module

Windows Server 2012 R2 and Windows 8.1 contain a nice function for import-PFXCertificate. However if you mange an older operating system you can use a different function:

function Import-PfxCertificate {
 
param([String]$certPath,[String]$certRootStore = “CurrentUser”,[String]$certStore = “My”,$pfxPass = $null)
$pfx = new-object System.Security.Cryptography.X509Certificates.X509Certificate2
 
if ($pfxPass -eq $null) {$pfxPass = read-host “Enter the pfx password” -assecurestring}
 
$pfx.import($certPath,$pfxPass,“Exportable,PersistKeySet”)

$store = new-object System.Security.Cryptography.X509Certificates.X509Store($certStore,$certRootStore)
$store.open(“MaxAllowed”)
$store.add($pfx)
$store.close()
}
Export-ModuleMember -Function 'Import-PfxCertificate'

Very basic hiding of words

Imagine a case where some user should fire up a script. You can specify credentials in plain text. However in some cases you shouldn’t want this. You can shuffle letters a bit so that an user cannot see the plain text password. You shouldn’t use this for anything higer than a low profile user account. Let’s say this is a test case.

Shuffle letters from CHAR To BYTE:

$Data = "Welkom01"
$Data=[CHAR[]]$data
$Pass = @()
Foreach ($letter in $Data){
$Pass += ([BYTE][CHAR]"$letter") 
}
write-host $pass -Separator " " -NoNewline

This will output 87 101 108 107 111 109 48 49

Shuffle letters from BYTE To CHAR:

$Data = "87 101 108 107 111 109 48 49"
$Data = $Data.Split(" ")
$Pass = @()
Foreach ($Item in $data) {$Pass += ([CHAR][BYTE]"$Item")}

$pass -join""

 

 

 

 

Suprise woman with days anniversary

Powershell can calculate basically everything. If you want the suprise someone with a number of days anniversary you can run the following code:

#Current date
$1 = get-date
#Old date
$2 = get-date 31/12/2009

($1 - $2).days

<#Something is returned. You can calculate to difference eq:
PS > 1561

Just run this code. It is as simple as a calculator
2000 - 1561
PS>439
#>

$1.AddDays(439)

Add Printer Script Unique Print Drivers

For an automated installation it was necessary to have an up to date list of the printer drivers. As print manufactorers occassionally add a dozen printer drivers into one setup we wanted to have a script that connects to all on duty print servers. I used the function Add-PrinterDriver for this cause. In the RES Automation Manager script there was some code necessary to first add a feature if it wasn’t present:

Import-Module ServerManager
$RSATADPowerShell = Get-WindowsFeature -Name "RSAT-AD-PowerShell"
If ($RSATADPowerShell.Installed -match "False"){
Add-WindowsFeature RSAT-AD-PowerShell}

Then I added the function in another script:

Import-Module ActiveDirectory
#Functie Add-PrinterDriver
function Add-PrinterDriver { 
 [CmdletBinding()] 
         Param( 
              [Parameter(Mandatory=$true)] 
              [string] $PrintServer, 
              [switch] $Clean 
             ) 

#Collecting all shared printer objects from the specified print server 
$allprinters = @(Get-WmiObject win32_printer -ComputerName $PrintServer -Filter 'shared=true') 
#Defining all unique printer drivers from the specified print server 
$drivers = @($allprinters | Select-Object drivername -Unique) 
#Defining a collection containing the first printer object using a unique printer driver 
$printers = @() 
foreach ($item in $drivers){ 
$printers += @($allprinters | Where-Object {$_.drivername -eq $item.drivername})[0] 
} 

#Collecting locally installed drivers 
$localdrivers = @() 
foreach ($driver in (Get-WmiObject Win32_PrinterDriver)){ 
$localdrivers += @(($driver.name -split ",")[0]) 
} 

#Initializing the CurrentPrinter variable for use with Write-Progress 
$CurrentPrinter = 1 

#Looping through the printer objects collection, installing those who are not already installed on the local computer 
foreach ($printer in $printers) { 

Write-Progress -Activity "Installing printers..." -Status "Current printer: $($printer.name)" -Id 1 -PercentComplete (($CurrentPrinter/$printers.count) * 100) 

#Create hash-table for output object 
$outputobject = @{} 
$outputobject.drivername = $printer.drivername 

$locallyinstalled = $localdrivers | Where-Object {$_ -eq $printer.drivername} 
if (-not $locallyinstalled) { 
Write-Verbose "$($printer.drivername) is not installed locally" 
$AddPrinterConnection = Invoke-WmiMethod -Path Win32_Printer -Name AddPrinterConnection -ArgumentList ([string]::Concat('\', $printer.__SERVER, '', $printer.ShareName)) -EnableAllPrivileges 
$outputobject.returncode = $AddPrinterConnection.ReturnValue 
} 
else 
{ 
Write-Verbose "$($printer.drivername) is already installed locally" 
$outputobject.returncode = "Already installed" 
} 

#Create a new object for each driver, based on the outputobject hash-table 
New-Object -TypeName PSObject -Property $outputobject 

$CurrentPrinter ++ 

} 

#Deletes all printer connections for the current user 
if ($clean) { 
$printers = Get-WmiObject Win32_Printer -EnableAllPrivileges -Filter network=true 
if ($printers) { 
foreach ($printer in $printers) { 
$printer.Delete() 
} 
} 
} 
}

$OS = (Get-WmiObject Win32_OperatingSystem).Caption.replace("Microsoft ","").Replace("Standard ","Standard").Replace("Enterprise ","Enterprise").Replace("Datacenter ","Datacenter")
$ADPrintservers = Get-ADComputer -Filter * -Property * |Where {$_.name -like "PR*"} | select DNSHostName,OperatingSystem
$Pingable =@()
foreach ($computer in $ADPrintservers){
if (Test-Connection $Computer.DNSHostName -quiet) { $Pingable += $Computer}}
foreach ($Computer in $Pingable){
If ($OS -contains $Computer.OperatingSystem){
Add-PrinterDriver -Printserver $Computer.DNSHostName}}

The script above enumerates all servers starting with PR*. Next this script test whether the server is pingable or not. You could enter credentials if you disabled pinging to the Test-Connection command. Next it validates if the server has the same OS as the print server. Some print servers are around for the 32 bit environment. You can also add a filter for that. At the end it deletes the space that is somehow added to the replace part of OS variable.  The bare function is like this:

function Add-PrinterDriver { 
 [CmdletBinding()] 
         Param( 
              [Parameter(Mandatory=$true)] 
              [string] $PrintServer, 
              [switch] $Clean 
             ) 

#Collecting all shared printer objects from the specified print server 
$allprinters = @(Get-WmiObject win32_printer -ComputerName $PrintServer -Filter 'shared=true') 
#Defining all unique printer drivers from the specified print server 
$drivers = @($allprinters | Select-Object drivername -Unique) 
#Defining a collection containing the first printer object using a unique printer driver 
$printers = @() 
foreach ($item in $drivers){ 
$printers += @($allprinters | Where-Object {$_.drivername -eq $item.drivername})[0] 
} 

#Collecting locally installed drivers 
$localdrivers = @() 
foreach ($driver in (Get-WmiObject Win32_PrinterDriver)){ 
$localdrivers += @(($driver.name -split ",")[0]) 
} 

#Initializing the CurrentPrinter variable for use with Write-Progress 
$CurrentPrinter = 1 

#Looping through the printer objects collection, installing those who are not already installed on the local computer 
foreach ($printer in $printers) { 

Write-Progress -Activity "Installing printers..." -Status "Current printer: $($printer.name)" -Id 1 -PercentComplete (($CurrentPrinter/$printers.count) * 100) 

#Create hash-table for output object 
$outputobject = @{} 
$outputobject.drivername = $printer.drivername 

$locallyinstalled = $localdrivers | Where-Object {$_ -eq $printer.drivername} 
if (-not $locallyinstalled) { 
Write-Verbose "$($printer.drivername) is not installed locally" 
$AddPrinterConnection = Invoke-WmiMethod -Path Win32_Printer -Name AddPrinterConnection -ArgumentList ([string]::Concat('\', $printer.__SERVER, '', $printer.ShareName)) -EnableAllPrivileges 
$outputobject.returncode = $AddPrinterConnection.ReturnValue 
} 
else 
{ 
Write-Verbose "$($printer.drivername) is already installed locally" 
$outputobject.returncode = "Already installed" 
} 

#Create a new object for each driver, based on the outputobject hash-table 
New-Object -TypeName PSObject -Property $outputobject 

$CurrentPrinter ++ 

} 

#Deletes all printer connections for the current user 
if ($clean) { 
$printers = Get-WmiObject Win32_Printer -EnableAllPrivileges -Filter network=true 
if ($printers) { 
foreach ($printer in $printers) { 
$printer.Delete() 
} 
} 
} 
}

This function lets powershell connect to the printserver. It does a query on all shared printers. Then it sorts the results to unique values. At last it connects to that printer which causes the driver to be installed. There is a group policy necessary for this to work. The following policy settings are mandatory:

PointAndPrintRestrictions

 

This is a computer policy located at Computer Configuration –> Windows Settings –> Printers –> Point and Print Restrictions

Account locked Out Randomly

A user was reporting that at random his AD Account was locked. He ensured me that he did not type his password wrong. After the first six reset I did not believe him. The user was an Administrator so I asked him if by any chance he installed any service under his name. He did change his password some time ago. We decided to revert to his old password. However the problem still occurred. I looked further into the problem. First searching why his account was locked out. On the first domain controller I ran a command:

Get-EventLog -LogName Security | ?{$_.entrytype -eq "FailureAudit" -and $_.message -match "SAMACCOUNTNAMEOFUSER"}

Change the SAMACCOUNTNAMEOFUSER to the sAMAccountname of the user. Add | FL for a larger output of the error.

This retured a set of four result. Three where at the exact same time one was some time after. The message was Kerberos Authentication Failed. The last time was the time that the user came to me saying his account was locked out again.

At the client address was an IP-address specified. It seemed that the Admin had an inactive session on that server or an scheduled task of some sort. Maybe even a service under his account.

I could not enter a pssession to that specific server. So I used a good old DOS Command:

query user /server:IPOFTHATSERVER

It retured the following output:

OutputQueryUser

This  session was logged on far before he changed his password. Maybe this account tried to log on to the domain with an old ticked which caused the DC to lock his account. Maybe he had an open file which occasionally tried to save with old credentials. It did however solve the problem

Random Password Generator

Generates strong passwords

PS1:

$length = 9
For ($a=48;$a –le 122;$a++) {$ascii+=,[char][byte]$a }
Function GET-Temppassword() {

Param(

[int]$length=10,

[string[]]$sourcedata

)

For ($loop=1; $loop –le $length; $loop++) {

            $TempPassword+=($sourcedata | GET-RANDOM)

            }

return $TempPassword

}

For ($a=48;$a –le 122;$a++) {$ascii+=,[char][byte]$a }

GET-Temppassword –length $Length –sourcedata $ascii

Optional Function:

Function GET-Temppassword() {

Param(

[int]$length=10,

[string[]]$sourcedata

)

For ($loop=1; $loop –le $length; $loop++) {

            $TempPassword+=($sourcedata | GET-RANDOM)

            }

return $TempPassword

}

ZIP: