Skip to content

Instantly share code, notes, and snippets.

@sean-m
Last active September 30, 2017 04:50
Show Gist options
  • Save sean-m/c610e492b8581ea185952381a8e60c39 to your computer and use it in GitHub Desktop.
Save sean-m/c610e492b8581ea185952381a8e60c39 to your computer and use it in GitHub Desktop.
Script that does string replacement on LDIF files. Not optimal for that exact purpose as it converts them to powershell objects first but if you ever need to parse an LDIF file into PowerShell objects here's a script to do that.
#Requires -Version 3
# Transforms objects from LDIF formatted file, parses file into PowerShell
# objects, then does string replace operations on all properties.
# Good Luck
# Works starts around line 170
####################################################################
## Functions ##
####################################################################
function Import-Ldif {
[CmdletBinding()]
[Alias()]
[OutputType([int])]
param (
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
Position=0)]
[object[]]$line)
begin {
$buf = New-Object System.Collections.Generic.Queue[string]
$new_entry = $true
$obj = $null
$prop = ''
$val = ''
$rgx_key = '^[a-zA-Z-]+(::|:)'
$rgx_data = '\s.+$'
function update-ldifobject {
if ($obj -eq $null) { return }
if (@($obj.PSObject.Properties.Name).Contains($prop)) {
$tmp = $obj.$prop
try {
$obj.$prop = @()
}
catch {
$_
}
$obj.$prop += $tmp
$obj.$prop += $val
}
else {
try {
$obj | Add-Member -MemberType NoteProperty -Name $prop -Value $val
}
catch {
$_
}
}
}
}
process {
if ($line.GetType() -like [string]) { $line = @($line) }
foreach ($l_ in $line) {
if ([String]::IsNullOrEmpty($l_)) {
$new_entry = $true
}
# parse value
if ($l_ -match $rgx_key) {
if (-not [String]::IsNullOrEmpty($val)) {
# create property
if ($new_entry) {
$obj = New-Object PSObject
$new_entry = $false
}
update-ldifobject
}
$val = [String]::Empty
$regx = [Regex]::Match($l_, $rgx_key)
$prop = $l_.Substring(0,$regx.Length)
if ($l_.Trim().Length -gt $regx.Length) {
try {
$val = $l_.Substring($regx.Length, $l_.Length-$regx.Length).Trim()
}
catch {
$_
}
}
}
elseif ($l_ -match $rgx_data) {
$val += $l_.Trim()
}
else {
update-ldifobject
$obj
$obj = $null
$val = ''
$prop = ''
$new_entry = $true
}
}
}
end {
if (-not $new_entry) {
update-ldifobject
$obj
}
}
}
function ConvertTo-Ldif
{
[CmdletBinding()]
[Alias()]
[OutputType([string])]
Param
(
# Param1 help description
[Parameter(Mandatory=$true,
ValueFromPipeline=$true,
Position=0)]
$LdifObj
)
Begin {
if (-not ([System.Management.Automation.PSTypeName]'StrHelper').Type) {
Add-Type -Language CSharp -TypeDefinition @"
using System;
using System.Text;
public static class StrHelper {
public static string LdifOutput (string key, string val) {
var sb = new System.Text.StringBuilder();
sb.Append(key);
int line = 1;
if (String.Join(" ", key, val).Length > 80) {
sb.Append("\n");
}
else {
line = sb.Length + 1;
}
sb.Append(' ');
for (int i=0; i < val.Length; i++) {
if (line == 79) {
sb.Append("\n ");
line = 1;
}
sb.Append(val[i]);
line++;
}
return sb.ToString();
}
}
"@
}
Function Write-LdifProp {
param ($prop, $val)
[StrHelper]::LdifOutput($prop, $val.ToString())
}
}
Process
{
# .GetType().BaseType -like [System.Array]
$props = @($LdifObj.PSObject.Properties.Name)
foreach ($p in $props) {
if ($LdifObj.$p.GetType().BaseType -like [System.Array]) {
foreach ($o in $LdifObj.$p) {
$str = Write-LdifProp $p $o
$str
}
}
else {
$str = Write-LdifProp $p $LdifObj.$p
$str
}
}
""
}
}
function percent {
param ($num,$div)
$pcnt = 0
$pcnt = ($num/$div) * 100
if ($pcnt -gt 100) { return 100 }
return $pcnt
}
####################################################################
## Configuration ##
####################################################################
## Values that will be replaces on LDIF objects
$subs = @{
"DC=test,DC=com"="DC=foo,DC=bar";
"test.com"="foo.bar";
}
## These values point to the ldif files
## that are read in and written out
$ldf_input = "domain.ldf"
$ldf_output = "C:\temp\tmp.ldf"
if ([String]::IsNullOrEmpty($ldf_input) -or
[String]::IsNullOrEmpty($ldf_output)) {
throw "`$ldf_input and `$ldf_output must be set!"
}
$obj_count = 0
$obj_total = 1
####################################################################
## Work ##
####################################################################
Write-Progress -Activity "Estimating record total"
## Streams are used here because it's 75x faster
## than Get-Content on files > 50MB
$fread = $null
try {
$fread = New-Object System.IO.StreamReader ($ldf_input)
while (-not ($fread.EndOfStream)) { if ([String]::IsNullOrEmpty($fread.ReadLine())) { $obj_total++ } }
} catch { throw }
finally { $fread.Dispose() }
## Parse objects and replace properties
$ldf_err = $null
gc $ldf_input -ReadCount 1000 | Import-Ldif | % {
$_ | % {
$_.PSObject.Properties } | % {
if ($_.Value) {
foreach ($s in $subs.Keys) {
$val = $subs[$s]
$_.Value = $_.Value.Replace($s, $val)
}
}
}
$obj_count++
Write-Progress -Activity "Transforming LDIF records." -CurrentOperation "Processed: $obj_count / $obj_total" -PercentComplete $(percent $obj_count $obj_total)
$_
} | ConvertTo-Ldif | Out-File -FilePath $ldf_output
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment