Posts RSS Comments RSS 253 Posts and 393 Comments till now

Archive for September, 2007

Citrix, Citrix, and more Citrix!

It has been a while since I dove into the MFCom pool. Most of the Citrix functions I wrote where at the very beggining of my Powershell Adventure. I decided to go through and rewrite some of them and post the others.

So… here you go.

I broke these down into three sections
- Citrix Farm Functions
- Citrix App Functions
- Citrix Server Functions

If you get a chance to use these let me know if you run into any troubles… I did test them thoroughly.. but you never know.

Other than Publish/Unpublish/Remove they shouldn’t change anything.

UPDATED: I added information about functions before each section. And a list at the bottom!

Farm functions
————–
# Returns Farm Object.
# -Server: Any PS should do.. I recommend ZDC though) !!REQ!!
Get-CitrixFarm

# Returns a collection of Server Objects
# -zone= This will be the zone name (normally the subnet i.e. 10.1.1.0) !!REQ!!
Get-CitrixOnline

# Returns Load Evaluators Information
# -Server: Any PS should do.. I recommend ZDC though) !!REQ!!
Get-CitrixLE

# Returns Printer Drivers install in Farm
# -Server: Any PS should do.. I recommend ZDC though) !!REQ!!
# This can take a REAL long time
Get-CitrixPrintDrivers

# Returns Polices in the Farm
# -Server !!REQ!! (any PS should do.. I recommend ZDC though)
Get-CitrixPolicies

#########################################
####     Citrix Farm Functions       ####
#########################################
# Get Citrix Farm
function Get-CitrixFarm{
    param($Server)
    $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeFarm",$Server)
    $mfarm = [system.Activator]::CreateInstance($type)
    $mfarm.Initialize(1)
    return $mFarm
}

# Get Online Servers by Zone
function Get-CitrixOnline {
    Param($zone)
    $mfzone = New-Object -ComObject MetaFrameCOM.MetaFrameZone
    $mfzone.Initialize($zone)
    $servers = $mfzone.OnlineServers
    $servers
}

# Get Citrix Load Evaluators (only 4.0/4.5)
function Get-CitrixLE{
    Param($server=$(throw "Server is Required"))
    function Load-Farm{
        param($srv)
        $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeFarm",$srv)
        $mfarm = [system.Activator]::CreateInstance($type)
        $mfarm.Initialize(1)
        return $mFarm
    }
    $Farm = load-farm $server
    if($Farm.LoadEvaluators){
        foreach($eval in $Farm.LoadEvaluators)
        {
            $eval.loadData(1)
            "+ Load Evaluator: {0}" -f $eval.LEName
            $servers = $eval.AttachedServers(1)
            if($servers.count -ne 0)
            {
                "  + Servers"
                $servers | %{"    - {0}" -f $_.ServerName}
            }
            $rules = $eval.rules | Select-Object RuleType,HWM,LWM,Schedules
            if($rules.count -ne 0)
            {
                "  + Rules"
                foreach($rule in $rules)
                {
                    "    - {0}" -f $rule
                }
            }
        }
    }
}

# Gets the Citrix Printer Drivers for the Farm (Can be REAL slow)
function Get-CitrixPrintDrivers{
    Param($server=$(throw "Server is Required"))
    function Load-Farm{
        param($srv)
        $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeFarm",$srv)
        $mfarm = [system.Activator]::CreateInstance($type)
        $mfarm.Initialize(1)
        return $mFarm
    }
    $farm = Load-Farm $Server
    $farm.Drivers
}

# Gets Citrix Policies
function Get-CitrixPolicies{
    param($Server)
    function Load-Farm{
        param($srv)
        $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeFarm",$srv)
        $mfarm = [system.Activator]::CreateInstance($type)
        $mfarm.Initialize(1)
        return $mFarm
    }
    $farm = Load-Farm $server
    $type = [System.Type]::GetTypeFromProgID("MetaFrameCOM.MetaFrameUserPolicy")
    foreach($pol in $Farm.policies($type))
    {
        $pol.loadData(1)
        "+ Name: {0}" -f $pol.Name
        "  - Description: {0}" -f $pol.Description
        "  - Enabled: {0}" -f $pol.Enabled
        if($pol.AllowedAccounts)
        {
            "  + AllowedAccounts"
            foreach($aa in $pol.AllowedAccounts)
            {
                "    - {0}" -f $aa.AccountName
            }
        }
        if($pol.UserPolicy2)
        {
            "  + UserPolicy"
            $props = $pol.UserPolicy2 | Get-Member -membertype Property | %{$_.Name} | Sort-Object Name
            foreach($prop in $props)
            {
                if(($pol.UserPolicy2.$prop -match "\d") -and ($pol.UserPolicy2.$prop -ne 0))
                {
                    "     – {0}:{1}" -f $prop,$pol.UserPolicy2.$prop
                }
            }
        }
        write-Output " "
    }
}

App functions
————–
# Returns User Count for an App or All Apps
# -FarmServer !!REQ!! (any PS should do.. I recommend ZDC though)
# -app: Name of Application
# This loops CTRL+C to break
Get-ApplicationUserCount

# Returns Server(s) user is logged into via Citrix
# -LoginName: Login Name of user (Domain\User) !!REQ!!
# -Verbose: Details about User
Find-CitrixUser

# Returns Servers published for Application or just Count
# -app: Name of Application !!REQ!!
# -count: Switch… if set just returns count of servers
Get-CitrixServers

# Returns Users currently using APP
# -app: !!REQ!!
# -count: Switch… if set just returns count of servers
Get-CitrixAppUsers

#########################################
####     Citrix App Functions        ####
#########################################
# Outputs the number of Users using a Citrix App or Apps
function Get-ApplicationUserCount {
    Param([string]$app,[string]$farmServer = $(throw ‘$FarmServer is Required’))
    function List-AllCitrixApps{
        Param($mFarm)
        ForEach($app in $mFarm.Applications)
        {
            $name = $app.BrowserName.PadRight(25)
            $count = "$($app.Sessions.Count)"
            $count = $count.PadRight(10)
            Write-Host "$name $count"
        }
    }
    function List-App{
        param($mApp,$mfFarm)
        ForEach($app in $mfFarm.Applications)
        {
            if($app.BrowserName -eq "$mApp")
            {
                $name = $app.BrowserName.PadRight(25)
                $count = "$(($app.Sessions | ?{$_.SessionState -eq 1}).Count)"
                $count = $count.PadRight(10)
                Write-Host "$name $count"
            }
        }
    }
    function Load-Farm{
        $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeFarm",$srv)
        $mfarm = [system.Activator]::CreateInstance($type)
        $mfarm.Initialize(1)
        return $mFarm
    }
    Write-Host
    $title1 = "Application".PadRight(25)
    $title2 = "===========".PadRight(25)
    Write-Host "$title1 User Count" -ForegroundColor White
    Write-Host "$title2 ==========" -ForegroundColor Red
    $mf = Load-Farm $farmServer
    While($true)
    {
        $oldpos = $host.UI.RawUI.CursorPosition
        If($app)
        {
            List-App $app $mf
        }
        else
        {
            List-AllCitrixApps $mf
        }
        sleep(5)
        $host.UI.RawUI.CursorPosition = $oldpos
    }
    Write-Host ""
}

# Finds what Server a User is on
function Find-CitrixUser {
    Param([string]$LoginName,[switch]$verbose)
    $user = $LoginName.Split("\")[1]
    $Domain = $LoginName.Split("\")[0]
    $mfuser = New-Object -ComObject MetaframeCOM.MetaframeUser
    $mfuser.Initialize(1,$Domain,1,$user)
    Write-Host
    Write-Host "User: $($mfuser.UserName) found on the Following:"
    foreach ($s in $mfuser.Sessions)
    {
        if($verbose)
        {
            Write-Host
            Write-Host "$($s.ServerName)"
            Write-Host "-=-=-=-=-=-"
            Write-Host "AppName          : $($s.AppName)" -foregroundcolor yellow
            Write-Host "SessionName      : $($s.SessionName)" -foregroundcolor yellow
            Write-Host "SessionID        : $($s.SessionID)" -foregroundcolor yellow
            Write-Host "ClientAddress    : $($s.ClientAddress)" -foregroundcolor yellow
            Write-Host "ClientEncryption : $($s.ClientEncryption)" -foregroundcolor yellow
            Write-Host
            Write-Host "Processes"
            Write-Host "========="
            foreach ($proc in $s.Processes)
            {
                Write-Host $proc.ProcessName -foregroundcolor Green
            }
            Write-host
        }
        else
        {
            write-Host "   -> $($s.ServerName)"
        }
    }
}

# Gets Servers Published for specified App (or just returns count)
function Get-CitrixServers {
    Param($app = $(throw ‘$app is required’),[switch]$count)
    $mfm = New-Object -com MetaFrameCOM.MetaFrameFarm
    $mfm.Initialize(1)
    $servers = $mfm.Applications | ?{$_.AppName -eq $app}
    $servers = $servers.Servers | sort -Property ServerName
    if($count)
    {
        Write-Host
        Write-Host "Found [$($Servers.Count)] Servers for Application [$app]" -ForegroundColor White
        Write-Host
    }
    else
    {
        Write-Host ""
        Write-Host "Found [$($Servers.Count)] Servers for Application [$app]" -ForegroundColor White
        Write-Host "———————————————–" -ForegroundColor gray
        foreach($server in $servers){Write-Host "$($server.ServerName)" -ForegroundColor Green}
        Write-Host "———————————————–" -ForegroundColor gray
        Write-Host "Found [$($Servers.Count)] Servers for Application [$app]" -ForegroundColor White
        Write-Host ""
    }
}

# Returns Users currently using Citrix App
function Get-CitrixAppUsers {
    Param($app = $(throw ‘$app is required’),[switch]$count)
    $ErrorActionPreference = "SilentlyContinue"
    Write-host
    $mfm = New-Object -com MetaFrameCOM.MetaFrameFarm
    $mfm.Initialize(1)
    $users = $mfm.Applications | ?{$_.AppName -eq $app}
    $Users = $users.Sessions | sort -Property UserName
    if($count){
        Write-Host "Found [$($Users.Count)] Users for Application [$app]" -ForegroundColor White
        Write-Host
    }
    else{
        Write-Host ""
        Write-Host "Found [$($Users.Count)] Users for Application [$app]" -ForegroundColor White
        Write-Host "—————————————————–" -ForegroundColor gray
        foreach($user in $Users){
            If($User.SessionState -eq 1){
                Write-Host ($User.UserName).PadRight(10) -ForegroundColor Green -NoNewline
            }
            else{
                Write-Host ($User.UserName).PadRight(10) -ForegroundColor yellow -NoNewline
            }
        }
        Write-Host
        Write-Host "—————————————————–" -ForegroundColor gray
        Write-Host "Found [$($Users.Count)] Users for Application [$app]" -ForegroundColor White
        Write-Host
    }
}

Server functions
————–
# Returns A Server Object
# -Server: Name of the Server !!REQ!!
Get-CitrixServer

# Publishes Application to Server(s)
# -app: !!REQ!!
# -Server: Name of Server
# PIPED: It will take Servers via Pipe. It expects a list or Citrix Server Object
Publish-CitrixApplication

# UnPublishes ALL Application from Server(s)
# -Server: Name of Server
# PIPED: It will take Servers via Pipe. It expects a list or Citrix Server Object
UnPublish-CitrixServer

# Remove Specific Application from Server(s)
# -app: !!REQ!!
# -Server: Name of Server
# PIPED: It will take Servers via Pipe. It expects a list or Citrix Server Object
Remove-CitrixApplication

# Gets Published Applications from Server(s)
# -Server: Name of Server
# PIPED: It will take Servers via Pipe. It expects a list or Citrix Server Object
Get-CitrixApplications

# Returns Count of Logged on Users from Server(s)
# -Server: Name of Server
# PIPED: It will take Servers via Pipe. It expects a list or Citrix Server Object
Get-TSUserCount

##########################################
####     Citrix Server Functions      ####
##########################################
# Get a Citrix Server Object
function Get-CitrixServer{
    Param($Server)
    $type = [System.Type]::GetTypeFromProgID("MetaframeCOM.MetaframeServer",$Server)
    $mfServer = [system.Activator]::CreateInstance($type)
    $mfServer.Initialize(6,$Server)
    $mfServer
}

# Publish Application to Server(s)
function Publish-CitrixApplication{
    Param([string]$server,[string]$app)
    Begin{
        Write-Host
        function cPublish {
            Param([string]$Srv,[string]$myapp)
            $Srv = $Srv.toUpper()
            $mfSrv = New-Object -ComObject MetaFrameCOM.MetaFrameServer
            $mfSrv.Initialize(6,"$Srv")
            $mfApp = New-Object -ComObject MetaFrameCOM.MetaFrameApplication
            $mfApp.Initialize(3,"Applications\$myapp")
            $mfApp.LoadData($true)
            $mfAppBinding = New-Object -ComObject MetaFrameCOM.MetaFrameAppSrvBinding
            $mfAppBinding.Initialize(6,$Srv,"Applications\$app")
            if($mfAppBinding)
            {
                Write-Host "Publishing App[$myapp] on Server [$Srv]" -ForegroundColor Green
                $mfApp.AddServer($mfAppBinding)
                $mfApp.SaveData()
            }
            else
            {
                Write-Host "Unable To Create App Binding" -ForegroundColor Red
            }
        }
        $process = @()
    }
    Process{
        if($_){
            if($_.ServerName){
                $process += $_.ServerName
            }
            else{
                $process += $_
            }
        }
    }
    End{
        if($Server){$Process += $Server}
        foreach($s in $process){
            cPublish -srv $s -myapp $app
            Write-Host
        }
    }
}

# UnPublish All Application from Server(s)
function UnPublish-CitrixServer{
    Param([string]$server)
    Begin{
        function cUnPublish {
            Param([string]$Srv)
            $Srv = $Srv.toUpper()
            $mfSrv = New-Object -ComObject MetaFrameCOM.MetaFrameServer
            $mfSrv.Initialize(6,"$Srv")
            If($mfSrv.Applications.Count -gt 0)
            {
                Write-Host "Removing All Published Applications from $Srv" -ForegroundColor Red
                Write-Host "===================================================" -ForegroundColor Green
                ForEach($a in $mfSrv.Applications)
                {
                    $myApp = $a.AppName
                    $a.LoadData(1)
                    Write-Host "Removing App [$myApp] from Server [$Srv]" -ForegroundColor White
                    $a.RemoveServer($Srv)
                    $a.SaveData()
                }
            }
            else
            {
                Write-Host "No Published Applications for $Srv" -ForegroundColor Red
            }
        }
        Write-Host
        $process = @()
    }
    Process{
        if($_){
            if($_.ServerName)
            {
                $process += $_.ServerName
            }
            else
            {
                $process += $_
            }
        }
    }
    End{
        if($Server){$Process += $Server}
        foreach($s in $process){
            cUnPublish $s
            Write-Host
        }
    }
}

# Remove a Citrix App from Server
function Remove-CitrixApplication {
    Param([string]$server,[string]$app)
    Begin{
        function RemoveApp {
            Param([string]$Srv,[string]$myapp)
            $AppRemoved = $false
            $Srv = $Srv.toUpper()
            $mfSrv = New-Object -ComObject MetaFrameCOM.MetaFrameServer
            $mfSrv.Initialize(6,"$Srv")
            If($mfSrv.Applications.Count -gt 0)
            {
                ForEach($a in $mfSrv.Applications)
                {
                    If($a.AppName -eq "$myapp")
                    {
                        Write-Host "Removing App [$myApp] from Server [$Srv]" -ForegroundColor Green
                        $a.RemoveServer($Srv)
                        $a.SaveData()
                        $AppRemoved = $true
                    }
                }
            }
            else
            {
                Write-Host "No Applications Published for $Srv" -ForegroundColor Red
                $AppRemoved = $true
            }
            If($AppRemoved -eq $false)
            {
                Write-Host "This Application not Published for $Srv" -ForegroundColor Red
            }
        }
        Write-Host
        $process = @()
    }
    Process{
        if($_)
        {
            if($_.ServerName){

                $process += $_.ServerName
            }
            else
            {
                $process += $_
            }
        }
    }
    End{
        if($Server){$Process += $Server}
        if($process.Length -eq 0){$Process += get-content env:COMPUTERNAME}
        foreach($s in $process)
        {
            RemoveApp -Srv $s -myapp $app
            Write-Host
        }
    }
}

# List Citrix Apps Published to Server
function Get-CitrixApplications {
    Param([string]$Server)
    Begin {
        Write-Host
        function cGetApps {
            param([string]$srv)
            $srv = $srv.ToUpper()
            $mfsrv = New-Object -ComObject MetaFrameCOM.MetaFrameServer
            $mfsrv.Initialize(6,"$srv")
            Write-Host "SERVER $srv" -foregroundcolor Red
            Write-Host "==================" -ForegroundColor Green
            If($mfSrv.Applications.Count -gt 0) {
                $mfSrv.Applications | %{Write-Host "Published:   $($_.AppName.ToUpper())"}
            }
            else {
                Write-Host "No Applications Published for $srv" -foregroundcolor white
            }
        }
        $process = @()
    }
    Process{
        if($_){
            if($_.ServerName){
                $process += $_.ServerName
            }
            else{
                $process += $_
            }
        }
    }
    End {
        if($Server){$Process += $Server}
        foreach($s in $process){
            cGetApps $s
            Write-Host
        }
    }
}

# Return Current Terminal Server User Count
function Get-TSUserCount {
    Param([string]$Server)
    Begin{
        function TsUserCount {
            param([string]$srv)
            $msg = "Checking For Users on Server [$srv]"
            $msg = $msg.PadRight($pad)
            Write-host $msg -ForegroundColor White
            $msg = "==========================================="
            $msg = $msg.PadRight($pad)
            Write-host $msg -ForegroundColor gray
            $msg = "Terminal Server User Count on Server "
            $msg1 = "[$srv]"
            $msg1 = $msg1.PadRight($pad)
            $ts = Get-WmiObject Win32_PerfFormattedData_TermService_TerminalServices -ComputerName $srv
            $count = $ts.activeSessions
            If($count -eq 0)
            {
                Write-host "$msg [Users:$count]" -ForegroundColor Green
            }
            else
            {
                Write-host "$msg [Users:$count]" -ForegroundColor Yellow
            }
        }
        $process = @()
    }
    Process{
        if($_){
            if($_.ServerName)
            {
                $process += $_.ServerName
            }
            else
            {
                $process += $_
            }
        }
    }
    End{
        if($Server){$Process += $Server}
        if($process.Length -eq 0){$Process += get-content env:COMPUTERNAME}
        foreach($s in $process)
        {
            TSUserCount $s
            Write-Host
        }
    }
}

Farm functions
————–
Get-CitrixFarm
Get-CitrixOnline
Get-CitrixLE
Get-CitrixPrintDrivers
Get-CitrixPolicies

App functions
————–
Get-ApplicationUserCount
Find-CitrixUser
Get-CitrixServers
Get-CitrixAppUsers

Server functions
————–
Get-CitrixServer
Publish-CitrixApplication
UnPublish-CitrixServer
Remove-CitrixApplication
Get-CitrixApplications
Get-TSUserCount

Test-Port (kinda like portqry without verbose output)

We had a little dicussion on www.powershelllive.com forums about the most efficient way to Test a machine before trying a WMI query against it (as it has a log timeout.) My first suggestion was to use a ping (WMI style) but Jeff from http://blog.sapien.com brought up a valid point… what if ICMP is NOT Allowed…

Enter Test-Port. This nifty little script uses the TCPClient Class to test connectivity. Stay tuned as I am planning some mods.

Test-Port
- Takes parameter $srv for Server Name
- Takes Parameter for Port, Defaults to 135 for RPC mapper.
- Takes Timeout.. defaults to 3000 (miliseconds)
- If it cannot connect within timeout… Returns $false
- If it gets exception connecting to port… Returns $false
- If it connects… Returns $True

function Test-Port{
    Param([string]$srv,$port=135,$timeout=3000,[switch]$verbose)
    $ErrorActionPreference = "SilentlyContinue"
    $tcpclient = new-Object system.Net.Sockets.TcpClient
    $iar = $tcpclient.BeginConnect($srv,$port,$null,$null)
    $wait = $iar.AsyncWaitHandle.WaitOne($timeout,$false)
    if(!$wait)
    {
        $tcpclient.Close()
        if($verbose){Write-Host "Connection Timeout"}
        Return $false
    }
    else
    {
        $error.Clear()
        $tcpclient.EndConnect($iar) | out-Null
        if($error[0]){if($verbose){write-host $error[0]};$failed = $true}
        $tcpclient.Close()
    }
    if($failed){return $false}else{return $true}
}

Run-Command.ps1 : Run External Commands with Power!

I was working late tonight and we had to run a bunch of third party EXEs and such. We do this a good bit so I can’t always avoid calling external executables and I also find psexec.exe much easier than any powershell way to run remote commands. That said I find myself constantly writing this.

$servers = Get-Content $file
foreach($server in $servers)
{
   Do Something Here Like
   psexec \\$server mycmd.exe param1
}

I decided to write a script call Run-Command.ps1.
This will take three parameters
- File (list of servers to process)
- Cmd (Command to run with %S% where you want the server name to be replaced)
- Check (just shows what command would run)
- Will also take Piped Input

Example:
PS> .\Run-Command.ps1 -file c:\serverlist.txt -cmd “psexec \\%S% mycmd.exe Hello World” -check

Run-Command.ps1

Param($file,$cmd,[switch]$whatif,[switch]$verbose)
Begin{
    function Ping-Server {
        Param([string]$srv)
        $pingresult = Get-WmiObject win32_pingstatus -f "address=’$srv’"
        if($pingresult.statuscode -eq 0) {$true} else {$false}
    }
    $servers = @()
}
Process{
    if($_)
    {
        if($_.ServerName){$servers += $_.ServerName}
        else{$servers += $_}
    }
}
End{
    if($file){Get-Content $file | %{$servers += $_}}
    foreach($server in $servers)
    {
        if(ping-server $server)
        {
            if($verbose){Write-Host "+ Processing Server $Server"}
            $mycmd = $cmd -replace "\%S\%",$Server
            if($whatif){Write-Host "  - WOULD RUN $mycmd"}
            else{if($verbose){Write-Host "  - Running $mycmd"};invoke-Expression $mycmd}
        }
        else
        {
            Write-Host "+ $Server FAILED PING" -foregroundcolor RED
        }
    }
}

Import-ADUser: All I can say is WoW! Posh 55 / Vbscript 210

Wow.. Just another example of Powershell Proving it is the BIG DOG in the Admin and scripting World!
55 lines vs 200+ line VBScript and the output is PRETTY! :)

CSV file should look like this although only Fullname/sAMAccountName/Mail are required
FullName,sAMAccountName,Mail,Title,Description,Department,manager,Groups
John Smith,jsmith,jsmith@lab.com,BossMan,IdaMaster,IT,me,”Tgroup1,Tgroup2,Tgroup3″

### Import-ADUsersFromCSV

Params($ImportFile,$Password = "P@ssW0rd!",$domain,$OU)
function Get-UserDN{
    Param($usr,$dom)
    $root = [ADSI]"LDAP://$dom"
    $filter = "(&(objectcategory=user)(sAMAccountName=$usr))"
    $searcher = New-Object System.DirectoryServices.DirectorySearcher($root,$filter)
    $searcher.findone() | %{$_.properties.distinguishedname}
}
function Add-UsertoGroup{
    param($group,$UserDN,$dom)
    $root = [ADSI]"LDAP://$dom"
    $filter = "(&(objectcategory=group)(Name=$Group))"
    $searcher = New-Object System.DirectoryServices.DirectorySearcher($root,$filter)
    $grp = ($searcher.findone()).GetDirectoryEntry()
    $grp.add("LDAP://$dom/$UserDN")
    $grp.SetInfo()
}
$Users = Import-Csv $ImportFile
foreach($user in $users)
{
    Write-Host "+ Creating User <$($User.FullName)>"
    # Checking for sAMAccountName/Mail/FullName
    if(!$user.sAMAccountName){Write-Host "  - User $($User.FullName) has no sAMAccountName";continue}
    if(!$user.mail){Write-Host "  - User $($User.FullName) has no mail";continue}
    if(!$user.fullname){Write-Host "  - User $($User.sAMAccountName) has no FullName";continue}
    if($user.ManagerName)
    {
        $manager = Get-UserDN $user.ManagerName -dom $domain
        Write-Host "  - Manager DN $Manager"
    }
    # Creating Account in OU
    $UserOU = [ADSI]"LDAP://$domain/$OU"
    $userObj = $UserOU.Create("User","CN=$($User.FullName)")
    $userObj.put("givenName",($user.FullName).Split()[0])
    $userObj.put("sn",($user.FullName).Split()[1])
    Write-Host "  - Setting User NTLogin $($user.sAMAccountName)";$userObj.put("samAccountName",$user.sAMAccountName)
    Write-Host "  - Setting User Email $($user.mail)";$userObj.put("mail",$user.mail)
    if($user.Designation)
    {Write-Host "  - Setting User Designation $($user.Title)";$userObj.put("Title",$user.Title)}
    if($user.Description)
    {Write-Host "  - Setting User Description $($user.Description)";$userObj.put("Description",$user.Description)}
    if($user.department)
    {Write-Host "  - Setting User Department $($user.department)";$userObj.put("department",$user.department)}
    $userObj.Setinfo()
    $userObj.psbase.invokeset(‘accountdisabled’, $false)
    $userObj.Setinfo()
    $userObj.psbase.invoke("setpassword",$password)
    $userObj.Setinfo()
    foreach($g in (($user.Groups).Split(",")))
    {
        Write-Host "  - Adding User to $g"
        Add-UsertoGroup -group $g -UserDN $userObj.distinguishedname -dom $domain
    }
    write-Host
}

###################################
OUTPUT
###################################

+ Creating User
– Manager DN CN=me,OU=MyUsers,DC=lab,DC=com
– Setting User NTLogin jsmith
– Setting User Email jsmith@lab.com
– Setting User Designation Loser
– Setting User Description Pretty Cool Guy
– Setting User Department IT
– Adding User to tgroup1
– Adding User to tgroup2

+ Creating User
– Manager DN CN=me,OU=MyUsers,DC=lab,DC=com
– Setting User NTLogin gsmith
– Setting User Email gsmith@lab.com
– Setting User Designation Loser
– Setting User Description Pretty Cool Guy
– Setting User Department Sales
– Adding User to tgroup1
– Adding User to tgroup2

Backup-EventLog

## UPDATED… ADDED a EVT format Script as Well ##

I saw a post on EE that backups up the eventlogs on Server using VBScript… I wanted to see what I could do with Powershell and this is what I came up with. I put this together pretty quick, so not much Error checking or anything, but the vbscript was 207 lines long without comments.

Basically it does the following
- Takes a BackupLoccation as a Parameter
- Takes a List file or a -FromAD switch
– List gets the computers from a file
– FromAD gets computers from AD
- Creates a Backup folder Named -Logs-
– Like Server1-Logs-09110750
- Processes Each Event Log and backs up to a File
- Clears Log
- I put the output of the script on the bottom.
- NOTE: Security Logs Take awhile. I assume this because I am Generating Events by Reading the Log.

Param($BackupLocation,$list,$FromAD)
function Get-ADComputers{
    $filter = "(&(objectcategory=computer))"
    $root = [ADSI]""
    $props = "dNSHostName","sAMAccountName"
    $Searcher = new-Object System.DirectoryServices.DirectorySearcher($root,$filter,$props)
    $Searcher.PageSize = 1000
    $Computers = $Searcher.findAll() | %{$_.properties[‘dnshostname’]}
    $Computers
}
function Ping-Server {
   Param([string]$server)
   $pingresult = Get-WmiObject win32_pingstatus -f "address=’$Server’"
   if($pingresult.statuscode -eq 0) {$true} else {$false}
}

if($FromAD){$computers = Get-ADComputers}
else{if($list){$computers = get-Content $list}else{Write-Host "Please Provide List";return}}

foreach($computer in $computers)
{
    $Folder = "{2}\{1}-Logs-{0:MMddyymm}" -f [DateTime]::now,$computer,$backupLocation
    Write-Host "+ Processing Server $Computer"
    new-Item $folder -type Directory -force  | out-Null

    if(Ping-Server $computer)
    {
        Write-Host "  + Created Backup Folder $folder"
        $eventlogs = [System.Diagnostics.EventLog]::GetEventLogs($computer)
        foreach($log in $eventlogs)
        {
            $LogFile = "{0}\{1}.csv" -f $Folder,$log.Log
            Write-Host "  + Processing $($log.Log) Log"
            Write-Host "    - Backing up $($log.Log)"
            $logEntries = $log.Entries | %{"{0},{1},{2},{3},{4}" -f $_.TimeGenerated,$_.EntryType,$_.Source,$_.EventID,$_.Message}
            $logEntries | out-File $LogFile -enc ASCII -width 500
            Write-Host "    - Backed up to $logFile"
            Write-Host "    - Clearing Log $($Log.Log)"
            $log.Clear()
        }
        Write-Host
    }
    else
    {
        Write-Host "Server $Computer failed PING!" -foregroundcolor red
    }
}

For those that perfer EVT format and WMI…. I left the Clear part commented

Param($BackupLocation,$list,$FromAD)

function Get-ADComputers{
    $filter = "(&(objectcategory=computer))"
    $root = [ADSI]""
    $props = "dNSHostName","sAMAccountName"
    $Searcher = new-Object System.DirectoryServices.DirectorySearcher($root,$filter,$props)
    $Searcher.PageSize = 1000
    $Computers = $Searcher.findAll() | %{$_.properties[‘dnshostname’]}
    $Computers
}
function Ping-Server {
   Param([string]$server)
   $pingresult = Get-WmiObject win32_pingstatus -f "address=’$Server’"
   if($pingresult.statuscode -eq 0) {$true} else {$false}
}

if($FromAD){$computers = Get-ADComputers}
else{if($list){$computers = get-Content $list}else{Write-Host "Please Provide List";return}}

foreach($computer in $computers)
{
    if(ping-server $computer)
    {
        $Folder = "{1}-Logs-{0:MMddyymm}" -f [DateTime]::now,$computer
        Write-Host "+ Processing Server $Computer"
        New-Item "$backupLocation\$folder" -type Directory -force  | out-Null
        If(!(Test-Path "\\$computer\c$\LogBackups")){New-Item "\\$computer\c$\LogBackups" -type Directory -force | out-Null}
        $Eventlogs = Get-WmiObject Win32_NTEventLogFile -ComputerName $computer
        Foreach($log in $EventLogs)
        {
            $path = "\\{0}\c$\LogBackups\{1}.evt" -f $Computer,$log.LogFileName
            $result = ($log.BackupEventLog($path)).ReturnValue
            Copy-Item $path -dest "$backupLocation\$folder" -force
            #if($result -eq 0){$log.ClearEventLog()}
        }
    }
}

NOTE: Shortly after writing this… I found this little tibit… it seems to have been around since SP3 of Win2000

Found it Here

http://blogs.msdn.com/spatdsg/default.aspx

AutoBackupLogFiles – backs up the event logs “Using this entry causes the Event Log service to automatically clear a full event log and to back up the log file. ”

http://support.microsoft.com/kb/312571

Sync Folder Script.

I initially wrote this for a guy on the NG, but I decided to use at work to sync some application folders I used to store tools and scripts and such. Please Try it out and tell me what you think.

Basic Flow
- Checks for Folders that Source has the Destination Does NOT and Creates.
- Checks for Folders that Destination has the Source Does NOT and Creates.
- Checks for files that Source has the Destination Does NOT and Copies.
- If the file is found in both, the MD5 of both files are checked… Last Write Wins
- Checks for Folders that Destination has the Source Does NOT
- It does NOT Delete anything yet… I am considering using a mirror switch

Param($Source,$Destination)
function Get-FileMD5 {
   Param([string]$file)
   $mode = [System.IO.FileMode]("open")
   $access = [System.IO.FileAccess]("Read")
   $md5 = New-Object System.Security.Cryptography.MD5CryptoServiceProvider
   $fs = New-Object System.IO.FileStream($file,$mode,$access)
   $Hash = $md5.ComputeHash($fs)
   $fs.Close()
   [string]$Hash = $Hash
   Return $Hash
}
function Copy-LatestFile{
    Param($File1,$File2,[switch]$whatif)
    $File1Date = get-Item $File1 | foreach-Object{$_.LastWriteTimeUTC}
    $File2Date = get-Item $File2 | foreach-Object{$_.LastWriteTimeUTC}
    if($File1Date -gt $File2Date)
    {
        Write-Host "$File1 is Newer… Copying…"
        if($whatif){Copy-Item -path $File1 -dest $File2 -force -whatif}
        else{Copy-Item -path $File1 -dest $File2 -force}
    }
    else
    {
        Write-Host "$File2 is Newer… Copying…"
        if($whatif){Copy-Item -path $File2 -dest $File1 -force -whatif}
        else{Copy-Item -path $File2 -dest $File1 -force}
    }
    Write-Host
}

if(!(test-Path $Destination))
{
    New-Item $Destination -type Directory -force | out-Null
}

# Getting Files/Folders from Source and Destination
$SrcEntries = Get-ChildItem $Source -Recurse
$DesEntries = Get-ChildItem $Destination -Recurse

# Parsing the folders and Files from Collections
$Srcfolders = $SrcEntries | Where-Object{$_.PSIsContainer}
$SrcFiles = $SrcEntries | Where-Object{!$_.PSIsContainer}
$Desfolders = $DesEntries | Where-Object{$_.PSIsContainer}
$DesFiles = $DesEntries | Where-Object{!$_.PSIsContainer}

# Checking for Folders that are in Source, but not in Destination
foreach($folder in $Srcfolders)
{
    $SrcFolderPath = $source -replace "\\","\\" -replace "\:","\:"
    $DesFolder = $folder.Fullname -replace $SrcFolderPath,$Destination
    if($DesFolder -ne ""){
        if(!(test-path $DesFolder))
        {
            Write-Host "Folder $DesFolder Missing. Creating it!"
            new-Item $DesFolder -type Directory | out-Null
        }
    }
}

# Checking for Folders that are in Destinatino, but not in Source
foreach($folder in $Desfolders)
{
    $DesFilePath = $Destination -replace "\\","\\" -replace "\:","\:"
    $SrcFolder = $folder.Fullname -replace $DesFilePath,$Source
    if($srcFolder -ne "")
    {
        if(!(test-path $SrcFolder))
        {
            Write-Host "Folder $SrcFolder Missing. Creating it!"
            new-Item $SrcFolder -type Directory | out-Null
        }
    }
}

# Checking for Files that are in the Source, but not in Destination
foreach($entry in $SrcFiles)
{
    $SrcFullname = $entry.fullname
    $SrcName = $entry.Name
    $SrcFilePath = $Source -replace "\\","\\" -replace "\:","\:"
    $DesFile = $SrcFullname -replace $SrcFilePath,$Destination
    if(test-Path $Desfile)
    {
        $SrcMD5 = Get-FileMD5 $SrcFullname
        $DesMD5 = Get-FileMD5 $DesFile
        If($srcMD5 -ne $desMD5)
        {
            Write-Host "The Files MD5′s are Different… Checking Write Dates"
            Write-Host $SrcMD5
            Write-Host $DesMD5
            Copy-LatestFile $SrcFullname $DesFile
        }
    }
    else
    {
        Write-Host "$Desfile Missing… Copying from $SrcFullname"
        copy-Item -path $SrcFullName -dest $DesFile -force
    }
}

# Checking for Files that are in the Destinatino, but not in Source
foreach($entry in $DesFiles)
{
    $DesFullname = $entry.fullname
    $DesName = $entry.Name
    $DesFilePath = $Destination -replace "\\","\\" -replace "\:","\:"
    $SrcFile = $DesFullname -replace $DesFilePath,$Source
    if($SrcFile -ne "")
    {
        if(!(test-Path $SrcFile))
        {
            Write-Host "$SrcFile Missing… Copying from $DesFullname"
            copy-Item -path $DesFullname -dest $SrcFile -force
        }
    }
}

Write-Host