Archive

Archive for the ‘Powershell Scripts’ Category

Export DHCP leases to HTML– version 2

An updated version of the previous script, now with the ability to export the MAC to the HTML as well as dumping all scopes to individual HTML and .csv files

param(
	[Parameter(Mandatory=$true)][String]$DHCPServer,
	[Parameter(Mandatory=$true)][string]$Scope,
	[switch]$IncludeMAC
	)

$sort = "DNS" #output file sorting, can also be "DNS" or "MAC" (MAC only if includeMAC switch selected

#####
#Functions
#####
Function DumpDHCPScope (){
Param(
	$subScope
)

$scopedump = (netsh dhcp server $DHCPServer scope $subScope show clients 1)
$lines = @()
foreach ($i in $scopedump){
	if ($i -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"){
		If ($i -match "[0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}"){	
			$lines += $i.Trim()
		}
	}
}
$csvfile = @()
foreach ($l in $lines){
	$Row = "" | select IP, DNS
	If ($IncludeMAC -eq $true){$Row = "" | select IP, DNS, MAC}
	#$l = $l -replace '[0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}', '' #removes MAC address
	$l = $l -replace ' - ',','
	$l = $l -replace '\s{4,}',''
	$l = $l -replace '--','-'
	$l = $l -replace '-D-','-'
	$l = $l -replace '[-]{1}\d{1,2}[/-]\d{1,2}[/-]\d{4}',''
	$l = $l -replace '\d{1,2}[:]\d{2}[:]\d{2}',''
	$l = $l -replace 'AM',''
	$l = $l -replace 'PM',''
	$l = $l -replace '[,][-]',''
	$l = $l -replace '\s{1}',','
	$l = $l -replace '[,]{2,4}',','
	$l = $l -replace '[,][-]',''
	#$l = $l + "`n"
	$Row.IP = ($l.Split(","))[0]
	#$Row.SubNetMask = ($l.Split(","))[1]
	if ($IncludeMAC -eq $true){$Row.MAC = ($l.Split(","))[2]}
	$Row.DNS = ($l.Split(","))[3]
	$csvfile += $Row
}

$csvfile | sort-object $sort | Export-Csv "C:\TMP\ScriptOut\$subScope-DHCPOut-List.csv" -NoTypeInformation

$a = "<style>"
$a = $a + "body {margin: 10px; width: 600px; font-family:arial; font-size: 12px;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
$a = $a + "TH{border-width: 1px;padding: 2px;border-style: solid;border-color: black;background-color: rgb(179,179,179);align='left';}"
$a = $a + "TD{border-width: 1px;padding: 2px;border-style: solid;border-color: black;background-color: white;}"
$a = $a + "</style>"

"Please contact theadminguy@wordpress.com in case of any questions" | Out-File "C:\TMP\ScriptOut\$subScope-DHCP-List.html"
$csvfile | sort-object $sort | ConvertTo-HTML -head $a | Out-File -Append "C:\TMP\ScriptOut\$subScope-DHCP-List.html"
get-date -Format dd/MM/yyyy@HH:mm:ss  | Out-File -Append "C:\TMP\ScriptOut\$subScope-DHCP-List.html"

}#End Function DumpDHCPScope

###
#Main Script
###

if ($Scope -eq "ALL"){
	$scopelist = @()
	$AllScopes = (netsh dhcp server $DHCPserver show scope 1)
	foreach ($i in $AllScopes){
		if ($i -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"){
			$scopelist += $i.Trim()
		}
	}
	Foreach ($i in $scopelist){
		$i = $i -replace '\s{2,}',''
		$i = $i -replace '- ',','
		$i = $i -replace '-',','
		DumpDHCPScope $i.Split(",")[0]
	}
}
Else {
	DumpDHCPScope $scope
}

Example commandlines:

Export-dhcptohtml.ps1 –dhcpserver 1.1.1.1 –scope 10.10.10.10 –includemac

This will dump the DHCP scope 10.10.10.10 including the MAC to an HTML file as well as a csv file.

Export-dhcptohtml.ps1 –dhcpserver 1.1.1.1 -scope ALL

This will dump all scopes on the dhcp server to individual HTML and .csv files.

Do post a comment, suggestion or request.

[Update 29-05-2012] – Added missing – (dash) in second example

/theadminguy

Categories: DHCP, Powershell Scripts

Copy certificates from one server to another

So for some reason, which until now remains a mystery, certificates where missing in the Trusted root certificate authorities certificate store on one of our servers.

Of course one of the missing ones, was the one needed for a main part of the servers purpose, so that had to be fixed.

While the certificates mmc does permit the export on the source server and the import onto the broken one, working in the GUI, is just….

So I cooked up a Powershell script to do the job for me:

<#
.SYNOPSIS
Compares a given certificate store between 2 Windows machines. Copies missing to target if specified

.DESCRIPTION
The script compares the specified certificate store of the source machine against the target machine. 
If the Write switch is specified, the missing certificates are copied from the source machine to the target machine

.PARAMETER SourceServer
Source Machine name

.PARAMETER TargetServer
Target Machine name

.PARAMETER CertStore
Certificate store to be checked
Possible values of the store: 
My - Personal Store
Root - Trusted root certificate authorities
CertificateAuthority - Intermediate certificate authorities
AuthRoot - Third-party certificate authorities

.PARAMETER write
If specified, certificates missing on the target server will be copied to the target server

.INPUTS
System.String

.OUTPUTS
Console output
Certificates 

.EXAMPLE
Check-MachineCerts.ps1 -SourceServer "SomeServer" -TargetServer "SomeServer" -certstore "AuthStore"
Outputs the certificates missing in the Third-party certificate authorities store on the target machine as compared to the source machine

.EXAMPLE
Check-MachineCerts.ps1 -SourceServer "SomeServer" -TargetServer "SomeServer" -certstore "My" -write
Outputs the certificates missing in the Personal Store on the target machine as compared to the source machine. 
Copies the missing certificates to the target machine

.NOTES
Check-MachineCerts.ps1
by theAdminGuy - theadminguy.wordpress.com
#>
Param(
	[Parameter(Mandatory=$true)][String]$SourceServer,
	[Parameter(Mandatory=$true)][String]$TargetServer,
	[Parameter(Mandatory=$true)]
		[ValidateSet("My","Root","CertificateAuthority","AuthRoot")]
		[String]$CertStore,
	[Parameter(Mandatory=$false)][switch]$write
)
#
#Connect to the source Root store (readonly)
$sourceStore = New-Object System.Security.Cryptography.X509Certificates.X509Store("\\$SourceServer\$CertStore","LocalMachine")
$sourceStore.open("ReadOnly")
#connect to the target store (readwrite)
$targetStore = New-Object System.Security.Cryptography.X509Certificates.X509Store("\\$TargetServer\$CertStore","LocalMachine")
$targetStore.open("ReadWrite")

$sourceCerts = $sourceStore.certificates
$targetCerts = $targetStore.certificates

Function CheckPrecense(){
Param(
    $sourcecert
)
	[int]$intCertFound = "0"
    $script:rtrCheckPrecense = "CertNotFound"
    ForEach ($targetcert in $targetCerts){     
        $test = $sourcecert.Equals($targetcert)
        if ($test -eq $true){
            $intCertFound++
        }
    }
    If ($intCertFound -ne "0"){
            $script:rtrCheckPrecense = "CertFound"
    }
} #end function 

foreach ($sourcecert in $sourceCerts){
    CheckPrecense $sourcecert
    If ($rtrCheckPrecense -eq "CertNotFound"){
        Write-Host `n`n $sourceCert.Subject " was not found on " $TargetServer
        If ($write -eq $true){
        	Write-Host `n "Copying Certificate from " $SourceServer `n
        	$targetStore.Add($sourceCert)
        }
    }
}

Don’t judge me by the fact that the .Synopsis part of the script takes up half the lines in the script, but not being a programmer by trade, I am trying to improve on my documentation skills (as well as making myself able to reuse the script once I have forgotten it’s original purpose)

The script can be easily modified to also remove certs from the target, which is not present on the source.

Do let me know all your input, thoughts etc.

 

/theadminguy

Remove privileged folder in Windows 7

Ever found yourself in the situation where you wanted to delete a folder in Windows 7, but you can’t because it has special rights in some way?

An example of such a folder could be the %windir%\winsxs.

In my case I had attached a virtual disk file (.vmdk) from one virtual machine to a new virtual machine.

So I wanted to clean this disk of the unneeded Windows folder, but as this folder as well as most of the subfolders are owned by TrustedInstaller, not by the local Administrators group. For the %windir%\winsxs folder, the administrators group as well as the local system user (NT Authority\System) has only read access to the files.

In order to delete the folder you have to do two things:

  1. Take ownership of the folder and files
  2. Grant the required user at least write access to the folder and files so they can be deleted

The above can be done using the %windir%\system32\takeown.exe and the %windir%\system32\Icacls.exe

If doing this on one machine, then you could just run the respective command lines:

  • takeown.exe /F d:\windows /R /D Y
  • Icacls.exe d:\windows /grant *<UserSID>:(F) /T /C

But if you ever have to repeat it, then it should have been scripted:

############
#Set-RestrictedFolderRights.ps1
#Set-RestrictedFolderRights -folder
############
param([string]$Folder="")
if($Folder -eq ""){Write-Host "Please specify folder...";Break}
############
#Functions
############

Function Get-UserSID(){
	$sCurrentUser = [system.environment]::UserName
	$sCurrentUserdomain = [system.environment]::Userdomain
	$objUser = New-Object System.Security.Principal.NTAccount($sCurrentUserdomain, $sCurrentUser)
	$strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
	$strSID.Value
}#end function Get-UserSID

############
#Main Script
############
$sSysFolder = ([system.environment]::SystemDirectory)
$sArgsA = '/F '+$Folder+' /A /R /D Y'

#grant ownership of the folder and all subfolders to the administrators group..
Start-Process -wait -FilePath "$sSysFolder\takeown.exe" -ArgumentList $sArgsA

#grant the logged on user full control of the folder and it's entire content
$sArgsB = $folder+' /grant *'+(Get-UserSID)+':(F) /T /C'
Start-Process -wait -FilePath "$sSysFolder\icacls.exe" -ArgumentList $sArgsB

The script takes the target folder as a parameter and then sets the rights:

PS > Set-RestrictedFolderRights -folder d:\Windows

After that the folder can be deleted.

A word of caution, there is no error checking in the script, so if you target the %systemroot% (usually c:\windows), the rights will be altered. As the script only adds permissions, the impact is not that huge, if the folder is not deleted after. But the rights are set in this manner for a reason

http://technet.microsoft.com/en-us/library/cc731677(WS.10).aspx

/theadminguy

Categories: Powershell Scripts

Export DHCP scopes and their address pools to a csv file

Because I love regular expressions, and I had a need for it, I have modified my previously posted DHCP export script:

$a = (netsh dhcp server 1.1.1.1 show scope)

$lines = @()
#start by looking for lines where there is IP present
foreach ($i in $a){
    if ($i -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"){
            $lines += $i.Trim()
    }
}

$csvfile = @()
$lines2 = @()
foreach ($l in $lines){
    $Row = "" | select Subnet,SubNetMask,ScopeStart,ScopeEnd,Location
    $l = $l + "`n"
    $l = $l -replace '-Active',''
    $l = $l -replace '-',','
    $l = $l -replace '\s',''
    $Row.Subnet = ($l.Split(","))[0]
    $c = $Row.Subnet
    $Row.SubNetMask = ($l.Split(","))[1]
    $Row.Location = ($l.Split(","))[2]
    $b = (netsh dhcp server 1.1.1.1 scope $c show iprange)
    foreach ($i2 in $b){
        if ($i2 -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" -and $i2 -notmatch 'Changed the current scope context to' `
            -and $i2 -notmatch 'No of IP Ranges : 1 in the Scope'){
            $lines2 += $i2.Trim()
        }
    }
    Foreach ($l2 in $lines2){
        $l2 = $l2 -replace '-',','
        $l2 = $l2 -replace '\s',''
        $Row.ScopeStart = ($l2.Split(","))[0]
        $Row.ScopeEnd = ($l2.Split(","))[1]
    }
    $csvfile += $Row
}    
$csvfile | sort-object Subnet | Export-Csv "C:\Users\Public\Documents\DHCPExport.csv"

The script put all the server scopes into a variable and then processes it.

As the netsh output is filled with headers and other stuff, quite a number of trims and –replacements are done.

The whole thing is then put into a csv file.

As usual any hints and pointers are welcomed.

/theadminguy

Modify Disk layout in Windows using powershell – updated version

At work one of my colleagues is fond of the phrase: Assume – makes and ass of you and me

Now this has, again, become very appropriate for me to use:

In my first post of the disk layout script, found here, I wrote with assumption and confidence: “but should also work on Windows Server 2003, if it does not then I have to redo the Altiris job”…

So I have redone the Altiris job powershell script:

#first we find and initialize physical disks with no partitions
$drives = gwmi Win32_diskdrive
$scriptdisk = $Null
$script = $Null
$OSversion = (((Get-WmiObject Win32_operatingsystem).version).ToString()).Split('.')[0]

foreach ($disk in $drives){
if ($disk.Partitions -eq "0"){
    $drivenumber = $disk.DeviceID -replace '[\\\\\.\\physicaldrive]',''
    
    If ($OSversion -eq "5"){
$script = @"
select disk $drivenumber
online noerr
create partition primary noerr
"@
    }
    ElseIf ($OSversion -eq "6"){
$script = @"
select disk $drivenumber
online disk noerr
attributes disk clear readonly noerr
create partition primary noerr
format quick
"@
}
    }
    $drivenumber = $Null
    $scriptdisk += $script + "`n"
    }
$scriptdisk | diskpart

#then we will move the CDRom drive to x:
(gwmi Win32_cdromdrive).drive | %{$a = mountvol $_ /l;mountvol $_ /d;$a = $a.Trim();mountvol x: $a}

#then we will assign letters and labels to physical drives
# thanks to powershell.com for this bit
#(http://powershell.com/cs/blogs/tips/archive/2009/01/15/enumerating-drive-letters.aspx)
$volumes = gwmi Win32_volume | where {$_.BootVolume -ne $True -and $_.SystemVolume -ne $True}
$letters = 68..89 | ForEach-Object { ([char]$_)+":" }
$freeletters = $letters | Where-Object { 
  (New-Object System.IO.DriveInfo($_)).DriveType -eq 'NoRootDirectory'
}
foreach ($volume in $volumes){
    if ($volume.DriveLetter -eq $Null){
        If ($OSVersion -eq "5"){
          mountvol $freeletters[0] $volume.DeviceID
          format $freeletters[0] /FS:NTFS /q /y
        }
        Else {
            mountvol $freeletters[0] $volume.DeviceID    
        }    
    }
$freeletters = $letters | Where-Object { 
    (New-Object System.IO.DriveInfo($_)).DriveType -eq 'NoRootDirectory'
}
} 

As it turns out, diskpart v5.2 does not support either the online disk command nor the format quick command, which is why I have had to add OS filtering (got to love the one-liner 🙂 and the format command.

I have also had to remove the $_.DriveType -eq "3", as an unformated primary partition under Windows Server 2003 R2 does not have a drivetype defined. But in order to salvage some honor, I’ll call that optimization, as it is actually not required, because that part of the script only assigns drive letters to volumes without one, and both the floppy and CDRom have one already.

/theadminguy

Export DHCP leases to html using powershell – update

There was a minor quirk in the original script, as lease dates where being mixed with hostnames in the final output html. As it turns out it was all a matter of what date it was, when I created the script 🙂

Line 21 in the original:

$l = $l -replace '[-]{1}\d{2}[/]\d{2}[/]\d{4}',''

matches dates in the following format: -xx/yy/zzzz but not -x/yy/zzzz or for that matter -xx/y/zzzz.

The correct –replace should have been:

$l = $l -replace '[-]{1}\d{1,2}[/]\d{1,2}[/]\d{4}',''

Thanks you for the comments, which was the final spark to get me to fix it in my production environment 🙂

Modify disk layout in Windows using powershell

So I have been configuring the company Altiris server (I love that tool) with some new jobs.

One of the headaches of past times, for me anyway, has been the modification of the disk layout, e.g. cd-rom must have letter so, a random number of physical disks must be formatted etc.

This is the powershell solution that I ended up with:

#first we find and initialize physical disks with no partitions 
$drives = gwmi Win32_diskdrive
$scriptdisk = $Null
$script = $Null
foreach ($disk in $drives){
    if ($disk.Partitions -eq "0"){
        $drivenumber = $disk.DeviceID -replace '[\\\\\.\\physicaldrive]',''        
$script = @"
select disk $drivenumber
online disk noerr
attributes disk clear readonly noerr
create partition primary noerr
format quick
"@
}
$drivenumber = $Null
$scriptdisk += $script + "`n"
}
$scriptdisk | diskpart

#then we will move the CDRom drive to x:
(gwmi Win32_cdromdrive).drive | %{$a = mountvol $_ /l;mountvol $_ /d;$a = $a.Trim();mountvol x: $a}

#then we will assign letters and labels to physical drives
# thanks to powershell.com for this bit
#(http://powershell.com/cs/blogs/tips/archive/2009/01/15/enumerating-drive-letters.aspx)
$volumes = gwmi Win32_volume | where {$_.BootVolume -ne $True -and $_.SystemVolume -ne $True -and $_.DriveType -eq "3"}
$letters = 68..89 | ForEach-Object { ([char]$_)+":" }
$freeletters = $letters | Where-Object { 
  (New-Object System.IO.DriveInfo($_)).DriveType -eq 'NoRootDirectory'
}
foreach ($volume in $volumes){
    if ($volume.DriveLetter -eq $Null){
        mountvol $freeletters[0] $volume.DeviceID
    }
$freeletters = $letters | Where-Object { 
    (New-Object System.IO.DriveInfo($_)).DriveType -eq 'NoRootDirectory'
}
} 

The script has been tested in PSHv2 installed on Windows Server 2008 and in native Windows 2008 R2 PSH, but should also work on Windows Server 2003, if it does not then I have to redo the Altiris job 🙂 – Update 14-11-2009: As it turns out the above will not work under Windows server 2003 – the updated version can be found here

The script first gets all the physical disks which have no partitions. Then it creates a script for use with diskpart. Once all physical disks are formatted, driveletters are assigned. First we move the cd-rom drive to x: then we loop through all volumes which are not BootVolume (e.g. c:\) or SystemVolume (W2k8 R2 reserved system partition)

Throw some comments or input to improve. I am particularly interested in a way to do this using .NET, so I do not have to use diskpart.

%d bloggers like this: