Powershell : WinSCP

WinSCP has a series of inbuilt libraries to help keep a remote site synchronised with a local site.

You will need WinSCP (obviously) and winscp.ino as well as WINSCPnet.dll.

I adapted the code a little more than listed here, but the premise is the same.

function Sync
{
param (
# Use Generate URL function to obtain a value for -sessionUrl parameter.
$sessionUrl = "sftp://somewhereelse-;fingerprint=ssh-rsa-long ssh key@notherecom",
[Parameter(Mandatory)]
$localPath,
[Parameter(Mandatory)]
$remotePath,
[Switch]
$delete = $False,
[Switch]
$beep = $False,
[Switch]
$continueOnError = $False,
$sessionLogPath = $Null,
$interval = 30,
[Switch]
$pause = $False
)

try
{
# Load WinSCP .NET assembly
$assemblyPath = if ($env:WINSCP_PATH) { $env:WINSCP_PATH } else { $PSScriptRoot }
Add-Type -Path (Join-Path $assemblyPath "WinSCPnet.dll")

# Setup session options
$sessionOptions = New-Object WinSCP.SessionOptions
$sessionOptions.ParseUrl($sessionUrl)

$session = New-Object WinSCP.Session

# Optimization
# (do not waste time enumerating files, if you do not need to scan for deleted files)
if ($delete)
{
$localFiles = Get-ChildItem -Recurse -Path $localPath
}

try
{
$session.SessionLogPath = $sessionLogPath

Write-Host "Connecting..."
$session.Open($sessionOptions)

while ($True)
{
Write-Host "Synchronizing changes..."
$result = $session.SynchronizeDirectories([WinSCP.SynchronizationMode]::Local, $localPath, $remotePath, $delete)

$changed = $False

if (!$result.IsSuccess)
{
if ($continueOnError)
{
Write-Host ("Error: {0}" -f $result.Failures[0].Message)
$changed = $True
}
else
{
$result.Check()
}
}

# Print updated files
foreach ($download in $result.Downloads)
{
Write-Host ("{0} <= {1}" -f $download.Destination, $download.FileName)
$changed = $True
}

if ($delete)
{
# scan for removed local files (the $result does not include them)
$localFiles2 = Get-ChildItem -Recurse -Path $localPath
$changes = Compare-Object -DifferenceObject $localFiles2 -ReferenceObject $localFiles

$removedFiles =
$changes |
Where-Object -FilterScript { $_.SideIndicator -eq "<=" } |
Select-Object -ExpandProperty InputObject

# Print removed local files
foreach ($removedFile in $removedFiles)
{
Write-Host ("{0} deleted" -f $removedFile)
$changed = $True
}

$localFiles = $localFiles2
}

if ($changed)
{
if ($beep)
{
[System.Console]::Beep()
}
}
else
{
Write-Host "No change."
}

Write-Host "Waiting for $interval seconds, press Ctrl+C to abort..."
$wait = [int]$interval
# Wait for 1 second in a loop, to make the waiting breakable
while ($wait -gt 0)
{
Start-Sleep -Seconds 1
$wait--
}

Write-Host
}
}
finally
{
Write-Host "Disconnecting..."
# Disconnect, clean up
$session.Dispose()
}
}
catch [Exception]
{
Write-Host ("Error: {0}" -f $_.Exception.Message)
}

# Pause if -pause switch was used
if ($pause)
{
Write-Host "Press any key to exit..."
[System.Console]::ReadKey() | Out-Null
}

# Never exits cleanly
#exit 1

}

 

Powershell : changing Remote Desktop Home Folders.

In my last blog I posted about finding the Remote Desktop Home Folders. Best now post how to change them …

Function Set-RDUserSetting {
[cmdletbinding(SupportsShouldProcess)]

Param(
[Parameter(Position=0,Mandatory,HelpMessage="Enter a user's sAMAccountName",
ValueFromPipeline,ParameterSetName="SAM")]
[ValidateNotNullorEmpty()]
[Alias("Name")]
[string]$SAMAccountname,
[Parameter(ParameterSetName="SAM")]
[string]$SearchRoot,

[Parameter(Mandatory,HelpMessage="Enter a user's distingished name",
ValueFromPipelineByPropertyName,ParameterSetName="DN")]
[ValidateNotNullorEmpty()]
[Alias("DN")]
[string]$DistinguishedName,

[boolean]$AllowLogon,
[Alias("Profile")]
[string]$TerminalServicesProfilePath,
[Alias("HomeDirectory")]
[string]$TerminalServicesHomeDirectory,
[Alias("HomeDrive")]
[string]$TerminalServicesHomeDrive,

[string]$Server,

[switch]$Passthru
)

Begin {
Write-Verbose "Starting $($MyInvocation.MyCommand)"
Write-Verbose ($PSBoundParameters | out-string)
#remote desktop properties
$TSSettings = @("TerminalServicesProfilePath","TerminalServicesHomeDirectory","TerminalServicesHomeDrive")
} #Begin

Process {

Write-Verbose "Using parameter set $($PSCmdlet.ParameterSetName)"
Switch ($PSCmdlet.ParameterSetName) {

"SAM" {
Write-Verbose "Retrieving distinguishedname for $samAccountname"
$searcher = New-Object DirectoryServices.DirectorySearcher
$searcher.Filter = "(&amp;(objectcategory=person)(objectclass=user)(samAccountname=$sAMAccountname))"
Write-Verbose $searcher.filter
if ($SearchRoot) {
Write-Verbose "Searching from $SearchRoot"
if ($Server) {
$searchPath = "LDAP://$server/$SearchRoot"
}
else {
$searchPath = "LDAP://$SearchRoot"
}
$r = New-Object System.DirectoryServices.DirectoryEntry $SearchPath

$searcher.SearchRoot = $r
}
$user = $searcher.FindOne().GetDirectoryEntry()
}
"DN" {
Write-Verbose "Processing $DistinguishedName"
if ($server) {
Write-Verbose "Connecting to $Server"
[ADSI]$User = "LDAP://$Server/$DistinguishedName"
}
else {
[ADSI]$User = "LDAP://$DistinguishedName"
}
}
} #close Switch

if ($user.path) {
if ($PSBoundParameters.ContainsKey("AllowLogon")) {
Write-Verbose "Configuring AllowLogon"
$user.psbase.invokeSet("AllowLogon",$AllowLogon -as [int])
}
foreach ($property in $TSSettings) {
if ($PSBoundParameters.ContainsKey($property)) {
Write-Verbose "Setting $property = $($PSBoundParameters[$property])"
$user.psbase.invokeSet($property,$PSBoundParameters[$property])
}
}
#commit changes
if ($PSCmdlet.ShouldProcess($DistinguishedName)){
$user.setInfo()
} #Whatif

if ($Passthru) {
$hash=[ordered]@{
DistinguishedName = $User.DistinguishedName.Value
Name = $user.name.Value
samAccountName = $user.samAccountName.value
AllowLogon = $user.psbase.InvokeGet("AllowLogon") -as [Boolean]
}

foreach ($property in $TSSettings) {
$hash.Add($property,$user.psbase.InvokeGet($property))

} #foreach

#create an object
New-Object -TypeName PSObject -Property $hash
}
} #if user found
else {
Write-Warning "Failed to find user $DistinguishedName"
}

} #Process

End {
Write-Verbose "Ending $($MyInvocation.MyCommand)"
} #End

} #end function

Powershell : Finding Remote Desktop Home Folders.

I am working on a project to migrate a Windows Cluster. I need to find any AD accounts that are pointing to the older cluster location in Remote Desktop Services Home Folder.

 

I have pilfered this code from the interwebs : https://www.petri.com/powershell-problem-solver-active-directory-remote-desktop-settings

 

[code language="powershell"]
Function Get-RDUserSetting {
 
[cmdletbinding(DefaultParameterSetName="SAM")]
 
Param(
[Parameter(Position=0,Mandatory,HelpMessage="Enter a user's sAMAccountName",
ValueFromPipeline,ParameterSetName="SAM")]
[ValidateNotNullorEmpty()]
[Alias("Name")]
[string]$SAMAccountname,
[Parameter(ParameterSetName="SAM")]
[string]$SearchRoot,
 
[Parameter(Mandatory,HelpMessage="Enter a user's distingished name",
ValueFromPipelineByPropertyName,ParameterSetName="DN")]
[ValidateNotNullorEmpty()]
[Alias("DN")]
[string]$DistinguishedName,
 
[string]$Server
 
)
 
Begin {
 Write-Verbose "Starting $($MyInvocation.MyCommand)"
 Write-Verbose ($PSBoundParameters | Out-String)
 #remote desktop properties
 $TSSettings = @("TerminalServicesProfilePath","TerminalServicesHomeDirectory","TerminalServicesHomeDrive")
} #Begin
 
Process {
 Write-Verbose "Using parameter set $($PSCmdlet.ParameterSetName)"
 Switch ($PSCmdlet.ParameterSetName) {
 
 "SAM" {
 Write-Verbose "Retrieving distinguishedname for $samAccountname"
 $searcher = New-Object DirectoryServices.DirectorySearcher
 $searcher.Filter = "(&(objectcategory=person)(objectclass=user)(samAccountname=$sAMAccountname))"
 Write-Verbose $searcher.filter
 if ($SearchRoot) {
 Write-Verbose "Searching from $SearchRoot"
 if ($Server) {
 $searchPath = "LDAP://$server/$SearchRoot"
 }
 else {
 $searchPath = "LDAP://$SearchRoot"
 }
 $r = New-Object System.DirectoryServices.DirectoryEntry $SearchPath
 
 $searcher.SearchRoot = $r
 }
 $user = $searcher.FindOne().GetDirectoryEntry()
 } 
 "DN" {
 Write-Verbose "Processing $DistinguishedName"
 if ($server) {
 Write-Verbose "Connecting to $Server"
 [ADSI]$User = "LDAP://$Server/$DistinguishedName"
 }
 else {
 [ADSI]$User = "LDAP://$DistinguishedName"
 }
 }
 } #close Switch
 
 if ($user.path) {
 #initialize a hashtable
 Try {
 $hash=[ordered]@{
 DistinguishedName = $User.DistinguishedName.Value
 Name = $user.name.Value
 samAccountName = $user.samAccountName.value
 AllowLogon = $user.psbase.InvokeGet("AllowLogon") -as [Boolean]
 }
 
 foreach ($property in $TSSettings) {
 $hash.Add($property,$user.psbase.invokeGet($property))
 
 } #foreach
 
 #create an object
 New-Object -TypeName PSObject -Property $hash
 }
 Catch {
 Write-Warning "Failed to retrieve remote desktop settings for $Distinguishedname. $($_.exception.message)"
 }
 } #if user found
 else {
 Write-Warning "Failed to find user $DistinguishedName. $($_.exception.message)"
 }
 
} #Process
 
End {
 Write-Verbose "Ending $($MyInvocation.MyCommand)"
} #End
 
} #end function
[/code]

 

 

Reset Admin Password in Windows 2012 without logging on

Instructions

To reset the password on your Windows 2012 server, simply complete the following steps:

  • Boot from the Micrsoft Windows Server 2012 DVD
  • From the Windows Setup menu, click “Next”.
  • Select “Repair your computer”
  • Under Choose and option, click on “Troubleshoot”.
  • Under Advanced options, click “Command Prompt”.
  • At the command prompt, run the following commands:
    d:
    cd windows\system32
    ren Utilman.exe Utilman.exe.old
    copy cmd.exe Utilman.exe
  • Close the command prompt and then click “Continue”.
  • The server should now boot and present the logon screen. Here click Windows Key + U.
  • At the prompt you can now change the password, by typing the following command:
    net user administrator Password123
    This will set the password for the Administrator user to be Password123 (case sensitive).

Closing the command prompt, you should now be able to log back onto the server using the password you have provided in the last step.

Cleanup Steps

Once you have verified you can log on to the server you will have repeat the steps above and boot using the Windows Server 2008 DVD/ISO and run the command prompt again.

  • Restart your server and once again, boot from the Micrsoft Windows Server 2012 DVD
  • From the Windows Setup menu, click “Next”.
  • Select “Repair your computer”
  • Under Choose and option, click on “Troubleshoot”.
  • Under Advanced options, click “Command Prompt”.
  • At the command prompt, run the following commands:
    d:
    cd windows\system32
    ren utilman.exe utilman.exe.new
    copy utilman.exe.old utilman.exe
  • Close the command prompt and then click “Continue”.

You should be back up and running as if nothing ever happened.

WSUS6.x Cannot open database “SUSDB” requested by the login. The login failed.~~Login failed for user ‘NT AUTHORITY\NETWORK SERVICE’

Are you receiving

Cannot open database “SUSDB” requested by the login. The login failed.~~Login failed for user ‘NT AUTHORITY\NETWORK SERVICE’ ?

 

Easy fix : Remove KB3159706

More complicated fix : https://support.microsoft.com/en-us/help/3159706/update-enables-esd-decryption-provision-in-wsus-in-windows-server-2012-and-windows-server-2012-r2

Powershell : Adding a GUI for a silent installer.

Seems counter intuative , right ?

Customer needs a pop up to display that software is being installed and offer the delay action. CM2012 could be used but it needs to be clear and simple for the (ab)users.

This happens to be for a SAP silent install , but the theory will work for all / any program.

###################################################################################################################################################################################################
# Coded By: Mr X
# Butchered by Bond
# Generated On: 07/12/2016 22:39.
# Version 1.3.2
# PreReq The required files need to copied to
# C:\$Batch$\Appscache\SAP7.40 including background image and .ico
###################################################################################################################################################################################################

#Small Functions
#Forms
#Function trigger calls
# Import the Assemblies for forms and drawings
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null

$objform = New-Object System.Windows.Forms.Form
$lblUpdates = New-Object System.Windows.Forms.Label
$lblUpdates1 = New-Object System.Windows.Forms.Label
$lblUpdates2 = New-Object System.Windows.Forms.Label
$okButton = New-Object System.Windows.Forms.Button
$DelayButton = New-Object System.Windows.Forms.Button
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#$a = 3 #number of delays allowed
#$DelayCount = 1 #initialise DelayCount
#$endprog = 0
function TimeDetection
{
$Time=Get-Date
$Time.AddHours(1).ToString("HH:mm:ss")
}
#not used
function GenratePopUp
{
[System.Windows.Forms.MessageBox]::Show("You cannot delay installation further" , "SAP Installation continuing")
}
#add reg key to run the script again if people power off / quit the installer

#Add into the registry
function AddRunOnce()
{
$BatchFix='$'+'batch$'
Write-Host "Adding RunOnce script." -foregroundcolor "magenta"
$RunOnceKey = "HKCU:\Software\Microsoft\Windows\CurrentVersion\RunOnce"
#set-itemproperty $RunOnceKey "NextRun" ('C:\Windows\System32\WindowsPowerShell\v1.0\Powershell.exe -executionPolicy Unrestricted -File ' + "C:\$BatchFix\appscache\SAP7.40\.SAPInstaller.ps1")
set-itemproperty $RunOnceKey "NextRun" ("C:\$BatchFix\appscache\EU_SAP_7.40_Extracted\setup\NWSAPSETUP.exe -ArgumentList /UPDATE /silent")

}

#removes runone from the registry
function RemoveRunOnce()
{
#removes reg key to run the script again if people power off / quit the installer
Write-Host "Remvoing RunOnce script." -foregroundcolor "magenta"
$RunOnceKey = "HKCU:\Software\Microsoft\Windows\CurrentVersion\RunOnce"
remove-itemproperty $RunOnceKey "NextRun"
}

#Preps the installer , terminates the saplgpad ( only works in 7.20 , then runs the installer )
function InstallSap()
{
stop-process -name saplgpad -Force -ErrorAction SilentlyContinue
Start-Process 'C:\$Batch$\appscache\EU_SAP_7.40_Extracted\setup\NWSAPSETUP.exe' -ArgumentList "/UPDATE /silent"
RemoveScheduledTask
RemoveRunOnce
}

#does what the function name says ..
function AddScheduledTask
{
$BatchFix='$'+'batch$'
$Time=Get-Date
$Start=$Time.ToString("HH:mm:ss")
$Delay=$Time.AddHours(1).ToString("HH:mm:ss")
$EndTime=$Time.AddHours(6).ToString("HH:mm:ss")
SchTasks /Create /SC DAILY /TN “SAP Powershell Task” /TR “powershell.exe -windowstyle hidden -file C:\$batchfix\appscache\SAP7.40\SAPGUIFinal.ps1 -ExecutionPolicy unrestricted” /ST $Start /ET $EndTime /RI 60
}

#guess ..
Function RemoveScheduledTask
{
#remove the schedule task
SchTasks /Delete /TN "SAP Powershell Task" /F
}

#Popup gnerator for informing users
function AndTheyAreOff
{
$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup("Installation underway. Please do not use SAP for 30Minutes",0,"SAP Installation",0x0)
}

# test function for the loop listed lower down. Not actually in use
function IExplore()
{
Start-Process iexplore.exe
exit
}

# test function for the loop listed lower down. Not actually in use
function SomethingElse()
{
Start-Process calc.exe
exit
}

#Couple of variables I needed , no functions as stored and called elsewhere.
$BatchFix='$'+'batch$'
$Time=Get-Date
$Start=$Time.ToString("HH:mm:ss")
$Delay=$Time.AddHours(1).ToString("HH:mm:ss")
$EndTime=$Time.AddHours(6).ToString("HH:mm:ss")

#Scheduled task installer check loop. There are no native PS commandlets in the kellogg deployed PS version so had to workaround
Function CheckIfTaskExists() {
$schedule = new-object -com Schedule.Service
$schedule.connect()
$tasks = $schedule.getfolder("\").gettasks(0)

foreach ($task in ($tasks | select Name)) {
echo "TASK : $($task.name)"
if($task.name.equals( "SAP Powershell Task")) {
write-output "$($task.name) already exists"
$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup("You have delayed once , you cannot delay again. Press OK to continue",0,"SAP Installation",0x0)
$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup("SAP Now installing, please leave 30 minutes before using again",0,"SAP Installation",0x0)
InstallSap
return
}
}
SchTasks /Create /SC DAILY /TN “SAP Powershell Task” /TR “powershell.exe -windowstyle hidden -file C:\$batchfix\appscache\SAP7.40\SAPGUIFinal.ps1 -ExecutionPolicy unrestricted” /ST $Start /ET $EndTime /RI 60
$wshell = New-Object -ComObject Wscript.Shell
$wshell.Popup("Delaying for 1h. The installer will automatically pop up in 1h",0,"SAP Installation",0x0)
$objform.Close()
return
}

#FORM below.

#GenerateForm
function GenerateForm {
#
$killprog=$endprog
$DelCount=$DelayCount
$b=$a
$OnLoadForm_StateCorrection=
{
#Correct the initial state of the form to prevent the .Net maximized form issue
$objform.WindowState = $InitialFormWindowState
}
$objform.AutoSize = $True
$objform.BackColor = [System.Drawing.Color]::FromArgb(255,255,255,255)
#ICON file specification
$Icon = New-Object system.drawing.icon ('C:\$Batch$\Appscache\EU_SAP_7.40_Extracted\favicon.ICO')
$objform.Icon = $Icon
#Background Image specified. Location C:\$Batch$\Appscache\EUSAPUpdates\Back1.bmp
$objform.BackgroundImage = [System.Drawing.Image]::FromFile('C:\$Batch$\Appscache\EU_SAP_7.40_Extracted\Background.png')
$objform.BackgroundImageLayout = 2
$System_Drawing_Size = New-Object System.Drawing.Size
#Window Size Specified
$System_Drawing_Size.Height = 600
$System_Drawing_Size.Width = 1000
$objform.ClientSize = $System_Drawing_Size
$objform.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",8.25,1,3,0)
$objform.FormBorderStyle = 5
$objform.Name = "objform"
$objform.Text = "EU SAP GUI 7.40 Upgrade"

#START Specify Attributes of Top Line Window text
$lblUpdates.BackColor = [System.Drawing.Color]::FromArgb(255,255,255,255)
$lblUpdates.DataBindings.DefaultDataSourceUpdateMode = 0
$lblUpdates.FlatStyle = 1
$lblUpdates.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",15,1,3,0)
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 155
$System_Drawing_Point.Y = 160
$lblUpdates.Location = $System_Drawing_Point
$lblUpdates.Name = "lblUpdates"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 50
$System_Drawing_Size.Width = 650
$lblUpdates.Size = $System_Drawing_Size
$lblUpdates.TabIndex = 3
$lblUpdates.Text = "Mandatory upgrade to SAP and Business Explorer Applications."
$lblUpdates.TextAlign = 2
#END Specify Attributes of Line 3 Box text
#Print Top Line of Box text
$objform.Controls.Add($lblUpdates)
#START Specify Attributes of Middle Line Window text
$lblUpdates1.DataBindings.DefaultDataSourceUpdateMode = 0
$lblUpdates1.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",16,5,3,0)
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 155
$System_Drawing_Point.Y = 225
$lblUpdates1.Location = $System_Drawing_Point
$lblUpdates1.Name = "lblUpdates1"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 50
$System_Drawing_Size.Width = 650
$lblUpdates1.Size = $System_Drawing_Size
$lblUpdates1.TabIndex = 5
$lblUpdates1.Text = "Please save and close all your work before continuing"
$lblUpdates1.TextAlign = 2
#END Specify Attributes of Middle Line Window text
#Print Middle Line of Window Text
$objform.Controls.Add($lblUpdates1)
#START Specify Attributes of Bottom Line Window text
$lblUpdates2.DataBindings.DefaultDataSourceUpdateMode = 0
$lblUpdates2.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",15,1,3,0)
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 155
$System_Drawing_Point.Y = 290
$lblUpdates2.Location = $System_Drawing_Point
$lblUpdates2.Name = "lblUpdates2"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 50
$System_Drawing_Size.Width = 650
$lblUpdates2.Size = $System_Drawing_Size
$lblUpdates2.TabIndex = 6
$lblUpdates2.Text = "Please click on OK button to continue"
$lblUpdates2.TextAlign = 2
#END Specify Attributes of Bottom Line Window text
#Print Boittom Line of Window text
$objform.Controls.Add($lblUpdates2)
#START Specify Attributes of Dev Button
$okButton.BackColor = [System.Drawing.Color]::FromArgb(255,220,220,220)
$okButton.DataBindings.DefaultDataSourceUpdateMode = 0
$okButton.FlatAppearance.BorderColor = [System.Drawing.Color]::FromArgb(255,0,0,0)
$okButton.FlatAppearance.BorderSize = 10
$okButton.FlatAppearance.MouseDownBackColor = [System.Drawing.Color]::FromArgb(255,0,0,0)
$okButton.FlatAppearance.MouseOverBackColor = [System.Drawing.Color]::FromArgb(255,0,0,0)
$okButton.FlatStyle = 3
$okButton.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",15,1,3,0)
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 300
$System_Drawing_Point.Y = 390
$okButton.Location = $System_Drawing_Point
$okButton.Name = "okButton"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 90
$System_Drawing_Size.Width = 175
$okButton.Size = $System_Drawing_Size
$okButton.TabIndex = 1
$okButton.Text = "OK - Continue"
#On Click of OK Button Close SAP
$okButton.add_Click(
{
$objform.Close()
AndTheyAreOff
InstallSap
RemoveRunOnce
}
)
$objform.Controls.Add($okButton)
#END Specify Attributes of OK Button and Publish button
#START Specify Attributes of Delay Button
$DelayButton.BackColor = [System.Drawing.Color]::FromArgb(255,220,220,220)
$DelayButton.FlatAppearance.BorderColor = [System.Drawing.Color]::FromArgb(255,0,0,0)
$DelayButton.DataBindings.DefaultDataSourceUpdateMode = 0
$DelayButton.FlatAppearance.BorderSize = 10
$DelayButton.FlatAppearance.MouseDownBackColor = [System.Drawing.Color]::FromArgb(255,0,0,0)
$DelayButton.FlatAppearance.MouseOverBackColor = [System.Drawing.Color]::FromArgb(255,0,0,0)
$DelayButton.FlatStyle = 3
$DelayButton.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",15,1,3,0)
$DelayButton.ForeColor = [System.Drawing.Color]::FromArgb(255,0,0,0)
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 480
$System_Drawing_Point.Y = 390
$DelayButton.Location = $System_Drawing_Point
$DelayButton.Name = "DelayButton"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 90
$System_Drawing_Size.Width = 175
$DelayButton.Size = $System_Drawing_Size
$DelayButton.TabIndex = 0
$DelayButton.Text = "Delay for 1Hour"
#On Click of Dev Button call CopyIni
$DelayButton.add_Click(
{
$objform.Close()
CheckIfTaskExists
#Exit

}
)

$objform.Controls.Add($DelayButton)
#END Specify Attributes of Standard Button and Publish button

#Save the initial state of the form
$InitialFormWindowState = $objform.WindowState

#Init the OnLoad event to correct the initial state of the form
$objform.add_Load($OnLoadForm_StateCorrection)

#Show the Form
$objForm.FormBorderStyle = 'Fixed3D'
$objForm.MaximizeBox = $false
$objForm.Visible = $false
$objform.ShowDialog()| Out-Null

$DelayCount = $DelCount
$a=$b
$endprog = $killprog
}

#END.Function GenerateForm

AddRunOnce
GenerateForm

Moving Windows 2008r2 Cluster Shares without DFS

You can move Windows 2008r2 cluster shares without the need for DFS.

It goes a little something like this

Data copy

I used emcopy to move all data from the existing sahre to the newly added share as it copies all and sundry. Quickly. Ill not go through these steps.

 

Adding Disk to services

Add in a new cluster disk , assign it to a new file server service that belongs to the existing file server role. Bring it all online , allocating a drive letter as you see fit

Add a file share to the existing shared disk. Give it a unique name ( you will see why later )

Add a file share to the newly added disk, again give it a new unique name.

 

 

Identifying Shares

Open regedit.

Search for the unique name on the existing share. Go slightly higher up the registry tree. Note parameters subkey. Note above that there is a long , long key. Copy that long identifier into notepad. Mark it something like existing share and finally paste in the long value

Repeat for the new share.

Save the notepad file just in case.

 

Moving Shares

Go back to regedit

Export the existing registry key from the long name. Name its something like ITS ALL GONE WRONG I NEED TO GET TO A SAFE PLACE.reg

Copy the reg file and paste it. Therefore duplicating it. Rename it Migration

Open/Edit it in notepad.

Replace every instance of the existing long key with the newly added key ( for the new drive ) you identified earlier. You are effectively here spoofing the old disk name with the new disk name

Replace every instance of the existing drive letter with the new shared disk. Save the newly tampered with reg file.

Take a brave pill now.

Drop all the share with the Manager shares and storage. You will be warned about dropping admin shares. Dont drop those.

Import the reg file you tampered with earlier.

Offline both Disk drives

Offline both file servers

Bring the Disk Drives back on

Bring the File server back on.

Hope and wait.

You should now have all the shares on the newly added drive. All the shares will have been dropped on the existing drive that we can assume will be retired

 

You *must* restart the cluster services on the passive node to refresh the passive nodes registry.

 

That should be it. I eyeballed the Shared Folder #client connections.

 

If you really , really want to use the old drive letter that was in existence, and I havent tested this : drop the now disused cluster disk from the failover cluster manager , re add a new RDM or independent persistent eager zero’d disk and allocate it the desired drive letter.

Do the same migration process detailed above.

 

 

 

 

 

SCCM Log files.

Ever wondered what the myriad of log files do ? Wonder no more !

https://technet.microsoft.com/en-gb/library/hh427342.aspx

Here is a great breakdown of the above information :

https://blogs.msdn.microsoft.com/lxchen/2009/04/03/a-list-of-sccm-log-files/

 

 

Powershell : Remove logon scripts

Removes logon scripts on a particular OU.

$path = [adsi]"LDAP://OU=Users,OU=IT,OU=Eu,DC=eu,DC=somewhere,DC=com"
$obj = New-Object adsisearcher($path , "(scriptPath=*)")
$users = $obj.FindAll()

foreach ($user in $users)
{
$user = [adsi]$user.path
$user.PutEx(1,"scriptPath",$null)
$user.SetInfo()
}

Powershell stop and restart multiple KDC

Powershell stop and restart multiple KDC

We had a requirement to stop and restart the KDC on multiple remote DCs.

Rather than go around each one , we wrote a script .

function DateAndTimeLog
{
Get-date
}
function testIf
{
If (Test-Connection -comp $dc -count 1 -quiet) {
$dc+" is online! "
}
Else {
$dc+" is offline, moving to next Domain Controller"
continue;
}

}
function SlowItDown
{
Start-Sleep -s 5
}

function MessageStop
{
Write-Host "stopping the KDC on $DC "
Write-Output "stopping the KDC on $DC "
}

function MessageStart
{
Write-Host "now restarting the KDC on $DC "
Write-Output "now restarting the KDC on $DC "
Write-Output "finished process"
Write-Output " ------------------ "
}

$File ="C:DCResults.txt"
$DCsinOurDomain= Get-ADDomainController -Filter *

ForEach($DC in $DCsinOurDomain.HostName){
DateAndTimeLog | Out-File $File -Append
testif | ft | Out-File $File -Append
(Get-WmiObject Win32_Service -filter "name='kdc'" -ComputerName $DC).StopService()
MessageStop | Out-File $File -Append
SlowItDown
(Get-WmiObject Win32_Service -filter "name='kdc'" -ComputerName $DC).StartService()
MessageStart | Out-File $File -Append

}

Powershell : Find all active users who havent logged in

Request from a customer. Find me all active ( IE not disabled ) users in a particular OU who have never logged in.

“I have a powershell for that” appears to be the default answer for most queries these days …

Get-ADUser -Filter {enabled -eq $true} -SearchBase "OU=Eu,DC=eu,DC=notyou,DC=com" -Properties "LastLogonDate" | sort-object -property lastlogondate -descending |Format-Table -property Name, sAMAccountName, LastLogonDate -AutoSize &gt;&gt;c:temptestoutput.csv

Powershell : remote machines static dns to DHCP

This will read an input file , and using the WMI object change any statically assigned DNS to DHCP.

 

# grabs the ListofMachines from the CSV
$ListofMachines=Get-Content “c:tempmachines.csv”
# loop starts here
foreach ($machine in $ListofMachines)
{
#Performs a release ( if needed ! use with care remotely ! )
#Get-WmiObject -Class Win32_NetworkAdapterConfiguration -ComputerName $machine | Where { $_.IpEnabled -eq $true -and $_.DhcpEnabled -eq $true} | ForEach-Object -Process {$_.ReleaseDHCPLease()}
# query the $machine that has the DHCP enabled adapter and performs the renewal
$wmi = Get-WmiObject win32_networkadapterconfiguration -computerName $machine -filter “ipenabled =’true'”;
$wmi.EnableDHCP();
$wmi.SetDNSServerSearchOrder();

Get-WmiObject -Class Win32_NetworkAdapterConfiguration -ComputerName $machine | Where { $_.IpEnabled -eq $true -and $_.DhcpEnabled -eq $true} | ForEach-Object -Process {ipconfig /flushdns}

}

Powershell : renew multiple machines DHCP scopes

# grabs the ListofMachines from the CSV
$ListofMachines=Get-Content “c:tempmachines.csv”
# loop starts here
foreach ($machine in $ListofMachines)
{
#Performs a release ( if needed ! use with care remotely ! )
#Get-WmiObject -Class Win32_NetworkAdapterConfiguration -ComputerName $machine | Where { $_.IpEnabled -eq $true -and $_.DhcpEnabled -eq $true} | ForEach-Object -Process {$_.ReleaseDHCPLease()}
# query the $machine that has the DHCP enabled adapter and performs the renewal
Get-WmiObject -Class Win32_NetworkAdapterConfiguration -ComputerName $machine | Where { $_.IpEnabled -eq $true -and $_.DhcpEnabled -eq $true} | ForEach-Object -Process {$_.RenewDHCPLease()}
Get-WmiObject -Class Win32_NetworkAdapterConfiguration -ComputerName 10.130.54.53 | Where { $_.IpEnabled -eq $true -and $_.DhcpEnabled -eq $true} | ForEach-Object -Process {ipconfig /flushdns}
#log for Output!
write-output “$machine has had IP renewed ” |out-file -filepath “c:tempresultsofDHCPLease04032015.csv” -append
}

Powershell : renew remote IP address

We wrote this at GiraffeIT.com. If you know the remote IP or DNS name of a machine it will help you renew a DHCP lease and flush the DNS.

Very useful if you have a remote machine with a scope change and its not being reflected.

 

write-host “—————————–”
write-host “DHCP lease renewal + flushDNS”
write-host “—————————–”
$machine = read-host “IP/Name of machine needing lease renewal ? ”
Get-WmiObject -Class Win32_NetworkAdapterConfiguration -ComputerName $machine | Where { $_.IpEnabled -eq $true -and $_.DhcpEnabled -eq $true} | ForEach-Object -Process {$_.RenewDHCPLease()}
Get-WmiObject -Class Win32_NetworkAdapterConfiguration -ComputerName $machine | Where { $_.IpEnabled -eq $true -and $_.DhcpEnabled -eq $true} | ForEach-Object -Process {ipconfig /flushdns}

Powershell – logon script based on username

Devised this script that will run a program based on the username of the logged in user and resizes the window as needed.

 

#find the currently logged on user and stick the name into the $LoggedOnUser variable
$LoggedOnUser=(Get-WmiObject -Class Win32_Process | Where-Object {$_.ProcessName -eq ‘explorer.exe’}).GetOwner() | select User
echo $LoggedOnUser

#Uncomment the line below and add into line 2 place if using on a local machine
#$LoggedOnUser=Get-WMIObject -class Win32_ComputerSystem | select username
#if statement now checking who is who.

If ($LoggedOnUser.user -eq “abc1”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc2”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc3”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc4”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc5”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc6”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc7”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc8”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc9”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc10”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc11”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc12”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc13”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc14”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc15”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc16”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc17”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abc18”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}
elseif ($LoggedOnUser.user -eq “abcz19”)
{
& “C:Windowstrace32.exe”
& “C:Windowsregedit.exe”
}

#final error trap : no username recognised ? Give them a popup box
else
{
[System.Reflection.Assembly]::LoadWithPartialName(“System.Windows.Forms”)
[Windows.Forms.MessageBox]::Show(“This account has not been assigned a citrix autorun. Now logging off ”, “Citrix Presentation”, [Windows.Forms.MessageBoxButtons]::OK, [Windows.Forms.MessageBoxIcon]::Information)
}

#makes sure the programs are open by delaying the script by 15 seconds
start-sleep -s 15
#find process now and move it
Add-Type @”
using System;
using System.Runtime.InteropServices;

public class Win32 {
[DllImport(“user32.dll”)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
}
“@
[int]$X = 960
[int]$Y = 0
[int]$nWidth = 960
[int]$nHeight =1080
[string]$processName = “proficyclient”

$handle = (Get-Process | where {$_.ProcessName -eq $processName}).MainWindowHandle

[Win32]::MoveWindow($handle, $X, $Y, $nWidth, $nHeight, $true )

#find second process
Add-Type @”
using System;
using System.Runtime.InteropServices;

public class Win32 {
[DllImport(“user32.dll”)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
}
“@
[int]$X = 0
[int]$Y = 0
[int]$nWidth = 960
[int]$nHeight =1080
[string]$processName = “vlc”

$handle = (Get-Process | where {$_.ProcessName -eq $processName}).MainWindowHandle

[Win32]::MoveWindow($handle, $X, $Y, $nWidth, $nHeight, $true )

$a = new-object -comobject wscript.shell
$b = $a.popup(“Please wait 15 seconds. This window will dissapear after 15 seconds “,15,”Wait”)

Powershell : export-dhcpserver

Export/Import existing scopes

 

Export the DHCP scope ( whilst leaving active on source ) from SERVER using either powershell or netsh

 

Powershell commands:

 

Export-DhcpServer [-File] <String> [-CimSession <CimSession> ] [-ComputerName <String> ] [-Force] [-Leases] [-Prefix <IPAddress[]> ] [-ScopeId <IPAddress[]> ] [ <CommonParameters>]

 

Example: export-dhcpserver -ComputerName SERVER -file “C:PATHNAME.XML”
Pre-Requisites for the PowerShell at that it is run on a windows 2012 server. The PowerShell will export it as an  XML file

 

To import the scope ( note that using the import-dhcpserver it DOES NOT overwrite any existing scopes )

 

Import-DhcpServer -file “C:PATHFILE.XML” -BackupPath “C:PATH”

 

 

NetSh verison :

 

This needs to be run on the server that holds the current DHCP scope that is being exported

 

Netsh export c:tempdhcpdb all

 

I prefer using PowerShell as I have tried and tested it. However it wont work with Windows 2003 servers

 

To import

Copy the .txt file that was created earlier and

 

netsh dhcp server import c:tempdhcp.txt all

 

Again this will NOT overwrite existing scopes. Refresh the window if it doesn’t appear.

Powershell: backup all DHCP servers

This script MUST be run on a 2012 server

#you define some share ( eg \server1dhcpbackup$  , and DNS suffix eg my.domain.com

#remove any variables that might have been stored, otherwise it has a bit of a wobble.
Remove-Variable dhcpServer
Remove-Variable dhcpServers

#we are going to do a check first for all files/folders that are older than X days ( you specify in the code )
# set folder path
$folderloc = “\somesharedhcpbackups$”

# set min age of files
$max_days = “70”

# get the current date
$curr_date = Get-Date

# determine how far back we go based on current date
$del_date = $curr_date.AddDays($max_days)

# delete the files
Get-ChildItem $folderloc -Recurse | Where-Object { $_.LastWriteTime -lt $del_date } | Remove-Item -Recurse -Confirm:$False

#this bit finds all the servers ( in the DC !) and only returns the chosen suffx ones as there are ones in the US
$dhcpServers= Get-DhcpServerInDC | where-object {$_.dnsname –match “dns suffix”}

#going to prepare a timestamp system now. l33t style.
$CurrentDate = Get-Date
$CurrentDate = $CurrentDate.ToString(‘dd-MM-yyyy_hh-mm-ss’)

#this bit loops and does the dhcp backup. Backs up the files locally to the path you can see, then copys the file to the $severloc ( which is in
#essence just the dhcpservers dns name )
foreach($dhcpServer in $dhcpServers){
$serverloc = $dhcpServer.DnsName
$from = “\$serverlocc$DHCPBackups”
backup-dhcpserver -ComputerName $dhcpserver.DnsName -Path “c:DHCPBackups”
Copy-Item $from \somesharedhcpbackups$$CurrentDate$serverloc -Recurse }

 

 

 

 

 

 

Powershell : Ping all machines

In theory you should know if all your machines are active or not in your environment. However as the environment gets bigger or more people work on it this can become confusing.

This powershell script reads a list ( in txt format ) of machines you want to ping , how many pings , max concurrent pings times to ping and gives you an output file. We cant claim any glory on the the script but we are sharing the knowledge

 

Param(
[parameter(Mandatory=$true)]
$InputFilePath,
[parameter(Mandatory=$true)]
$MaxConcurrent,
[parameter(Mandatory=$true)]
$TimesToPing,
$TimeoutInSeconds,
$ResolveNames
)

$Start = [System.DateTime]::Now
Write-Host “Version 1.0”
Write-Host “InputFilePath:”$InputFilePath
Write-Host “MaxConcurrent:”$MaxConcurrent
Write-Host “TimesToPing:”$TimesToPing
Write-Host “TimeoutInSeconds:”$TimeoutInSeconds
Write-Host “ResolveNames:”$ResolveNames

function GetNamesFromTextFile
{
param($file)

$ht = @{}

try
{
foreach ($line in [System.IO.File]::ReadLines($file))
{
try { $ht.Add($line.ToString().Trim(), $line.ToString().Trim()) } catch {}
}
}
catch
{
Write-Host “Failed to Read File, Exiting:”$ms -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Yellow
exit
}

return $ht
}

function GetStatusCodeString
{
param ($code)

switch ($code)
{
$null {$ret = “Ping Command Failed”}
0 {$ret = “Success”}
11001 {$ret = “Buffer Too Small”}
11002 {$ret = “Destination Net Unreachable”}
11003 {$ret = “Destination Host Unreachable”}
11004 {$ret = “Destination Protocol Unreachable”}
11005 {$ret = “Destination Port Unreachable”}
11006 {$ret = “No Resources”}
11007 {$ret = “Bad Option”}
11008 {$ret = “Hardware Error”}
11009 {$ret = “Packet Too Big”}
11010 {$ret = “Request Timed Out”}
11011 {$ret = “Bad Request”}
11012 {$ret = “Bad Route”}
11013 {$ret = “TimeToLive Expired Transit”}
11014 {$ret = “TimeToLive Expired Reassembly”}
11015 {$ret = “Parameter Problem”}
11016 {$ret = “Source Quench”}
11017 {$ret = “Option Too Big”}
11018 {$ret = “Bad Destination”}
11032 {$ret = “Negotiating IPSEC”}
11050 {$ret = “General Error”}
default {$ret = “Ping Failed”}
}

return $ret
}

function GetPingResultsFromHashTable
{
param($ht, $maxConcurrent, $count, $timeout)

$bDone = $false
$i = 0
$totalMachines = 0
$htResults = @{}
$dotTime = [System.DateTime]::Now
if ($timeout -eq $null) {$timeout = 120}

Write-Host (“Sending Ping Command to {0} Machines” -f $ht.Count) -NoNewline

foreach ($name in $ht.GetEnumerator())
{
while ((Get-Job -State Running).Count -ge $maxConcurrent)
{
Start-Sleep -Seconds 1
if ($i -ge 50) { Write-Host “*”; $i = 0 }
else { Write-Host “*” -NoNewline; $i++ }
}

$job = Test-Connection -ComputerName $name.Key.ToString() -Count $count -AsJob
$job.name = “ping:{0}” -f $name.Key.ToString()

if ([System.DateTime]::Now -gt $dotTime)
{
$dotTime = ([System.DateTime]::Now).AddSeconds(1)
if ($i -ge 50) { Write-Host “.”; $i = 0 }
else { Write-Host “.” -NoNewline; $i++ }
}
}

#Start time now, exit in case of timeout
$timeout = ([System.DateTime]::Now).AddSeconds($timeout)
$dotTime = [System.DateTime]::Now
$i = 0
Write-Host
Write-Host “Getting Ping Results” -NoNewline

while(!($bDone))
{
$results = Get-Job -Name ‘ping:*’
$bRunning = $false

foreach ($result in $results)
{
if ($result.State -ne ‘Running’)
{
if ($result.State -eq ‘Failed’)
{
#resubmit job
if ($i -ge 50) { Write-Host “+”; $i = 0 }
else { Write-Host “+” -NoNewline; $i++ }
$job = Test-Connection -ComputerName $result.Name.ToString().Split(“:”)[1] -Count $count -AsJob
$job.name = “ping:{0}” -f $result.Name.ToString().Split(“:”)[1]
}
else
{
try { $htResults.Add($result.Name.ToString().Split(“:”)[1], (Receive-Job $result)) } catch {}
$totalMachines++
}

if ([System.DateTime]::Now -gt $dotTime)
{
$dotTime = ([System.DateTime]::Now).AddSeconds(1)
if ($i -ge 50) { Write-Host “.”; $i = 0 }
else { Write-Host “.” -NoNewline; $i++ }
}

try { Remove-Job $result } catch {}
}
else
{
$bRunning = $true
}
}

#Check for timeout condition, clean up all jobs if true
if ([System.DateTime]::Now -gt $timeout)
{
$bDone = $true
Write-Host “Timeout reached, removing jobs”
$results = Get-Job -Name ‘ping:*’
foreach ($result in $results)
{
Write-Host “RemoveJob:”$result.Name
try
{
Stop-Job $result
try { Remove-Job $result -Force } catch {}
}
catch {}
}
}

#If the timeout hasn’t been reached and jobs are still running, loop again
if (!($bRunning)) { $bDone = $true }
}

Write-Host
Write-Host (“Received Ping Results From {0} Machines” -f $totalMachines)

return $htResults
}

function ResolveNamesFromPingResults
{
param($array, $maxConcurrent, $resolveNames, $timeout)

try { if ($resolveNames -ne $null) { [bool]$resolveNames = [System.Convert]::ToBoolean($resolveNames) } } catch {}

$htResults = @{}

if ($resolveNames)
{
$dotTime = ([System.DateTime]::Now)
if ($timeout -eq $null) {$timeout = 120}
$i = 0
$scriptBlock =
{
param($s)
try { $ret = [System.Net.DNS]::GetHostEntry($s) } catch {}
return $ret
}
Write-Host (“Resolving DNS Names for {0} Machines” -f $array.Count) -NoNewline
foreach ($name in $array)
{
while ((Get-Job -State Running).Count -ge $maxConcurrent)
{
Start-Sleep -Seconds 1
if ($i -ge 50) { Write-Host “*”; $i = 0 }
else { Write-Host “*” -NoNewline; $i++ }
}
$job = Start-Job -ScriptBlock $scriptBlock -ArgumentList $name.NameInList
$job.name = “resolve:{0}” -f $name.NameInList
if ([System.DateTime]::Now -gt $dotTime)
{
$dotTime = ([System.DateTime]::Now).AddSeconds(1)
if ($i -ge 50) { Write-Host “.”; $i = 0 }
else { Write-Host “.” -NoNewline; $i++ }
}
}

#Start time now, exit in case of timeout
$timeout = ([System.DateTime]::Now).AddSeconds($timeout)
$dotTime = ([System.DateTime]::Now)
$i = 0
$bDone = $false

Write-Host
Write-Host “Getting DNS Results” -NoNewline
while(!($bDone))
{
$results = Get-Job -Name ‘resolve:*’
$bRunning = $false

foreach ($result in $results)
{
if ($result.State -ne ‘Running’)
{
if ($result.State -eq ‘Failed’)
{
#resubmit job
if ($i -ge 50) { Write-Host “+”; $i = 0 }
else { Write-Host “+” -NoNewline; $i++ }
$job = Start-Job -ScriptBlock $scriptBlock -ArgumentList $result.Name.ToString().Split(“:”)[1]
$job.name = “resolve:{0}” -f $result.Name.ToString().Split(“:”)[1]
}
else
{
try { $htResults.Add($result.Name.ToString().Split(“:”)[1], (Receive-Job $result)) } catch {continue}
}

if ([System.DateTime]::Now -gt $dotTime)
{
$dotTime = ([System.DateTime]::Now).AddSeconds(1)
if ($i -ge 50) { Write-Host “.”; $i = 0 }
else { Write-Host “.” -NoNewline; $i++ }
}

try { Remove-Job $result -Force} catch {}
}
else
{
$bRunning = $true
}
}

#Check for timeout condition, clean up all jobs if true
if ([System.DateTime]::Now -gt $timeout)
{
$bDone = $true
Write-Host “Timeout reached, removing jobs”
$results = Get-Job -Name ‘resolve:*’
foreach ($result in $results)
{
Write-Host “RemoveJob:”$result.Name
try
{
Stop-Job $result
try { Remove-Job $result -Force } catch {}
}
catch {}
}
}

#If the timeout hasn’t been reached and jobs are still running, loop again
if (!($bRunning)) { $bDone = $true }
}
Write-Host
Write-Host (“Received DNS Results From {0} Machines” -f $htResults.Count)
}

return $htResults
}

function GetFormattedPingResultsFromHashTable
{
param($ht)

$fResults = New-Object System.Collections.ArrayList
$dotTime = ([System.DateTime]::Now)
$i = 0
Write-Host “Formatting Ping Results” -NoNewLine

foreach ($result in $ht.GetEnumerator())
{
#There are multiple pings here if we ping more than once per computer
$originalAddress = $result.Key.ToString()
$pingCount = 0
$successCount = 0
$status = ‘Ping Job Failed’
$pingedFrom = ‘Ping Job Failed’
$successPercentage = 0

try { $pings = $result.Value.Count } catch { $pings = 0 }
if ($pings -gt 0)
{
$status = GetStatusCodeString -code $result.Value[$pings-1].StatusCode
$pingedFrom = $result.Value[$pings-1].PSComputerName
}

foreach ($ping in $result.Value)
{
$pingCount++
if ($ping.StatusCode -eq 0) { $successCount++ }
#If you try to get the IPv4Address or IPv6Address it slows down this loop significantly
}

#Calculate percentage
if ($pingCount -ne 0) { $successPercentage = ($successCount / $pingCount) * 100 }
else { $successPercentage = 0 }

#Add to array
$o = New-Object PSObject -Property @{
NameInList = $originalAddress
PingedFrom = $pingedFrom
SuccessPercentage = $successPercentage
LastPingStatus = $status
}

[void]$fResults.Add($o)

if ([System.DateTime]::Now -gt $dotTime)
{
$dotTime = ([System.DateTime]::Now).AddSeconds(1)
if ($i -ge 50) { Write-Host “.”; $i = 0 }
else { Write-Host “.” -NoNewline; $i++ }
}
}

Write-Host
Write-Host (“Formatted Ping Results for {0} Machines” -f $fResults.Count)

return $fResults
}

function GetFormattedPingAndDNSResults
{
param($pingResults, $dnsResults)

if ($dnsResults.Count -ne 0)
{
Write-Host “Formatting DNS Results” -NoNewLine
$dotTime = ([System.DateTime]::Now)
$i = 0
foreach ($ping in $pingResults)
{
$dns = $dnsResults.Get_Item($ping.NameInList)
if ($dns -ne $null)
{
$bFirst = $true
foreach ($ip in $dns.AddressList)
{
if ($bFirst){ $ipList = $ip }
else { $ipList += “|” + $ip }
}

$fqdn = $dns.HostName
}
else
{
$ipList = $null
$fqdn = ‘No DNS Entry Found’
}

$ping | Add-Member -MemberType NoteProperty -Name NameFromDNS -value $fqdn -Force
$ping | Add-Member -MemberType NoteProperty -Name IPAddressListFromDNS -value $ipList -Force

if ([System.DateTime]::Now -gt $dotTime)
{
$dotTime = ([System.DateTime]::Now).AddSeconds(1)
if ($i -ge 50) { Write-Host “.”; $i = 0 }
else { Write-Host “.” -NoNewline; $i++ }
}
}
Write-Host
Write-Host (“Formatted DNS Results for {0} Machines” -f $pingResults.Count)
}

return $pingResults
}

function GetOutputPath
{
param($fileName, $dir)
$outputPath = $dir + “” + $fileName
return $outputPath
}

function GetTimeSpanStringInMinutesAndSeconds
{
param($startTime, $endTime)

$time = $startTime.Subtract($endTime)
$minutes = $time.ToString().Split(“:”)[1]
$seconds = $time.ToString().Split(“:”)[2].Split(“.”)[0]
$timeSpan = “{0} Minutes and {1} Seconds” -f $minutes, $seconds
return $timeSpan
}

function GetSuccessPingCount
{
param($results)

$successCount = 0
foreach ($result in $results)
{
if ($result.SuccessPercentage -gt 0) { $successCount++ }
}

return $successCount
}

function GetDNSNamesResolvedCount
{
param($results)

$namesResolved = 0
foreach ($result in $results)
{
if ($result.IPAddressListFromDNS -ne $null) { $namesResolved++ }
}

return $namesResolved
}

function GetPercentageAsString
{
param($n1, $n2)

if ($n1 -ne 0) { $percentage = ($n1 / $n2) * 100 }
else { $percentage = 0 }

$percentage = (“{0:N0}” -f $percentage) + “%”

return $percentage
}

#Read in Names from text file
$Names = GetNamesFromTextFile -file $InputFilePath

#Get ping results in a hash table. The key is the name and the value is the returned array of ping objects (one element per ping).
$Results = GetPingResultsFromHashTable -ht $Names -maxConcurrent $MaxConcurrent -count $TimesToPing -timeout $TimeoutInSeconds

#Format ping results into an array of objects
$FormattedPingResults = GetFormattedPingResultsFromHashTable -ht $Results

#Resolve DNS Names if specified
$DNSResults = ResolveNamesFromPingResults -array $FormattedPingResults -maxConcurrent 5 -resolveNames $ResolveNames -timeout $TimeoutInSeconds

#Format DNS results by adding them to the ping results
$FormattedPingResults = GetFormattedPingAndDNSResults -pingResults $FormattedPingResults -dnsResults $DNSResults

#Output to CSV
$OutputPath = GetOutputPath -fileName ‘PingResults.csv’ -dir ([Environment]::CurrentDirectory=(Get-Location -PSProvider FileSystem).ProviderPath)
try { if ($ResolveNames -ne $null) { [bool]$ResolveNames = [System.Convert]::ToBoolean($ResolveNames) } } catch {}
if ($ResolveNames) { $FormattedPingResults | Sort-Object SuccessPercentage | Select-Object NameInList, NameFromDNS, IPAddressListFromDNS, SuccessPercentage, LastPingStatus, PingedFrom | Export-Csv -Path $OutputPath -NoTypeInformation }
else { $FormattedPingResults | Sort-Object SuccessPercentage | Select-Object NameInList, SuccessPercentage, LastPingStatus, PingedFrom | Export-Csv -Path $OutputPath -NoTypeInformation }

#Output Statistics
$SuccessPingCount = GetSuccessPingCount -results $FormattedPingResults
Write-Host “—Statistics—” -ForegroundColor Green
Write-Host (“Total Time Elapsed: ” + (GetTimeSpanStringInMinutesAndSeconds -startTime $Start -endTime ([System.DateTime]::Now))) -ForegroundColor Green
Write-Host “Total Names Pinged:”$FormattedPingResults.Count -ForegroundColor Green
Write-Host (“Hosts that Responded: ” + ($SuccessPingCount)) -ForegroundColor Green
Write-Host (“DNS Names Resolved: ” + (GetDNSNamesResolvedCount -results $FormattedPingResults)) -ForegroundColor Green
Write-Host (“Percentage of Hosts that Responded at Least Once: ” + (GetPercentageAsString -n1 $SuccessPingCount -n2 $FormattedPingResults.Count)) -ForegroundColor Green
Write-Host “CSV Output Location:”$OutputPath -ForegroundColor Yellow

Powershell : Find all servers in a domain

This code will find all servers in a domain and return its canonical location

 

$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.Filter = ‘(OperatingSystem=Window*Server*)’
“Name”,”canonicalname”,”distinguishedname” | Foreach-Object {$null = $objSearcher.PropertiesToLoad.Add($_) }
$objSearcher.FindAll() | Select-Object @{n=’Name’;e={$_.properties[‘name’]}},@{n=’ParentOU’;e={$_.properties[‘distinguishedname’] -replace ‘^[^,]+,’}} | ft -autosize

Powershell : add users from one group to another.

Simple script to add multipe users from one group to another easily.

 

Will show on screen error if they already are members of the destination group but carry on going on error.

 

 

======================================================================================

$Source_Group = “CN=MAC,OU=Test Groups,OU=Groups,OU=GB,,DC=whatever,DC=com”

$Destination_Group = “CN=newMAC,OU=Test Groups,OU=Groups,OU=GB,,DC=whatever,DC=com”

 

$Target = Get-ADGroupMember -Identity $Source_Group

foreach ($Person in $Target) {

Add-ADGroupMember -Identity $Destination_Group -Members $Person.distinguishedname

}

 

Powershell export virtual machines IP

This script is pretty handy, it will connect to the Virtual Center you specify in Powershell.

 

# you will need to adjust the viserver name
connect-viserver mecvm01.eu.kellogg.com

$reportedvms=New-Object System.Collections.ArrayList
$vms=get-view -viewtype virtualmachine |Sort-Object -Property { $_.Config.Hardware.Device | where {$_ -is [VMware.Vim.VirtualEthernetCard]} | Measure-Object | select -ExpandProperty Count} -Descending

foreach($vm in $vms){
$reportedvm = New-Object PSObject
Add-Member -Inputobject $reportedvm -MemberType noteProperty -name Guest -value $vm.Name
Add-Member -InputObject $reportedvm -MemberType noteProperty -name UUID -value $($vm.Config.Uuid)
$networkcards=$vm.guest.net | ?{$_.DeviceConfigId -ne -1}
$i=0
foreach($ntwkcard in $networkcards){
Add-Member -InputObject $reportedvm -MemberType NoteProperty -Name “networkcard${i}.Network” -Value $ntwkcard.Network
Add-Member -InputObject $reportedvm -MemberType NoteProperty -Name “networkcard${i}.MacAddress” -Value $ntwkcard.Macaddress
Add-Member -InputObject $reportedvm -MemberType NoteProperty -Name “networkcard${i}.IpAddress” -Value $($ntwkcard.IpAddress|?{$_ -like “*.*”})
Add-Member -InputObject $reportedvm -MemberType NoteProperty -Name “networkcard${i}.Device” -Value $(($vm.config.hardware.device|?{$_.key -eq $($ntwkcard.DeviceConfigId)}).gettype().name)
$i++
}
$reportedvms.add($reportedvm)|Out-Null
}

$reportedvms|Export-Csv c:myreport.csv