Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using namespace System.IO
- using namespace System.Xml.Linq
- [Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq") | Out-Null
- $ErrorActionPreference = "Stop"
- function Reserve-WritePermissions
- {
- Param
- (
- [Parameter(Mandatory)]
- [Alias("LockfilePath")]
- [PSObject]$lockfile_path
- )
- #Attempt to create the lock file. If this fails, someone else is already updating.
- try
- {
- $lock_stream = [System.IO.File]::Open($lockfile_path, [FileMode]"CreateNew", [FileAccess]"ReadWrite")
- $lock_writer = [System.IO.StreamWriter]::new($lock_stream)
- $lock_writer.WriteLine([Environment]::UserName)
- $lock_writer.WriteLine([DateTime]::Now.ToString())
- return $true #We were able to reserve write permissions
- }
- catch
- {
- $permissions = Check-WritePermissions -LockfilePath $lockfile_path
- if($permissions -eq $null)
- {
- Write-Host "When you first attempted to reserve write permissions, a reservation already existed." -ForegroundColor Red
- Write-Host "By the time we checked to see who had reserved it, the reservation had already cleared." -ForegroundColor Red
- Write-Host "Please try again." -ForegroundColor Red
- }
- else
- {
- Notify-NoWritePermissions -PermissionsObject $permissions -LockfilePath $lockfile_path
- }
- }
- finally
- {
- if($lock_writer -ne $null)
- { $lock_writer.Dispose() }
- if($lock_stream -ne $null)
- { $lock_stream.Dispose() }
- }
- return $false
- }
- function Check-WritePermissions
- {
- Param
- (
- [Parameter(Mandatory)]
- [Alias("LockfilePath")]
- [string]$lockfile_path
- )
- if((Test-Path $lockfile_path) -eq $false)
- { return $null }
- try
- {
- $lock_contents = Get-Content $lockfile_path
- return Create-WritePermissionsObject -LockfileContents $lock_contents
- }
- catch [System.Management.Automation.ItemNotFoundException]
- {
- # We *HAD* a lock file, but it was deleted in between our previous test, and this one
- # So, return $null indicating that we SHOULD have permissions
- return $null
- }
- }
- function Notify-NoWritePermissions
- {
- Param
- (
- [Parameter(Mandatory)]
- [Alias("PermissionsObject")]
- [PSObject]$permissions_object,
- [Parameter(Mandatory)]
- [Alias("LockfilePath")]
- [PSObject]$lockfile_path
- )
- if($permissions_object -eq $null)
- { $permissions_object = Check-WritePermissions -LockfilePath $lockfile_path }
- if(($permissions_object -eq $null) -or ($permissions_object.DateTime -eq [DateTime]::MinValue))
- {
- Write-Host "There was a problem checking for an existing reservation." -ForegroundColor Red
- Write-Host "Please ensure there is no one updating the database, then delete the file located at $lockfile" -ForegroundColor Red
- return
- }
- Write-Host "$($permissions_object.Username) has been updating the database since $($permissions_object.DateTime)." -ForegroundColor Red
- Write-Host "Please wait for $($permissions_object.Username) to complete their work." -ForegroundColor Red
- Write-Host "If you would like to cancel the session, and discard their changes:" -ForegroundColor Red
- Write-Host "`tIf possible, contact $($permissions_object.Username) to confirm they are not working on anything important." -ForegroundColor Red
- Write-Host "`tThen, delete the file located at $lockfile" -ForegroundColor Red
- return
- }
- function Create-WritePermissionsObject
- {
- Param
- (
- [Parameter(Mandatory)]
- [Alias("LockfileContents")]
- [string[]]$lockfile_contents
- )
- if($lock_contents.Length -ne 2)
- {
- return New-Object PSObject -Property @{
- 'Username' = "Unknown"
- 'DateTime' = [DateTime]::MinValue
- }
- }
- $datetime = [DateTime]::MinValue
- # I don't need to check to see if this succeeded. If it didn't, the DateTime will be [DateTime]::MinValue, which is what I'm using to signal failure.
- [DateTime]::TryParse($lock_contents[1], [ref]$datetime)
- return New-Object PSObject -Property @{
- 'Username' = $lock_contents[0]
- 'DateTime' = $datetime
- }
- }
- function CommitOrCancel-Changes
- {
- Param
- (
- [Parameter(Mandatory)]
- [XElement]$database,
- [Parameter(Mandatory)]
- [Alias("DatabasePath")]
- [string]$database_path,
- [Parameter(Mandatory)]
- [Alias("LockfilePath")]
- [string]$lockfile_path,
- [Parameter(Mandatory)]
- [bool]$commit
- )
- #Before saving the file, make *SURE* we have permissions. It's possible someone has revoked our permissions in the meantime.
- $permissions_object = Check-WritePermissions -LockfilePath $lockfile_path
- if($permissions_object -eq $null)
- {
- #Somehow, we lost permissions, and no one else has them.
- #If we're cancelling, just exit the function; we don't have the permissions anyway
- if($commit -eq $false)
- { return $true } #We were able to cancel
- #We're committing...
- #So, try to reserve them again. If this works, just move on.
- if((Reserve-WritePermissions -LockfilePath $lockfile_path) -eq $false)
- { #If it fails, notify and abort
- Notify-NoWritePermissions -PermissionsObject $null -LockfilePath $lockfile_path
- return $false #We were not able to commit
- }
- }
- else
- {
- #We have a permissions object. Make sure it's ours.
- if($permissions_object.Username -ne [Environment]::UserName)
- {
- Notify-NoWritePermissions $permissions_object -LockfilePath $lockfile_path
- return $false
- }
- }
- #By now, we have confirmed that we have permissions.
- #If we're committing....
- if($commit)
- {
- #Go ahead and save the file. There is a small chance of a race condition happening, and we may overwrite someone's changes.... We've done our best.
- $database.Save($database_path)
- }
- #Delete our reservation
- Remove-Item $lockfile_path
- return $true
- }
- function Open-Write
- {
- Param
- (
- [Parameter(Mandatory)]
- [Alias("DatabasePath")]
- [string]$database_path,
- [Parameter(Mandatory)]
- [Alias("LockfilePath")]
- [string]$lockfile_path
- )
- # First, just check to see if someone has a reservation, instead of trying to make one first.
- $reservation = Check-WritePermissions -LockfilePath $lockfile_path
- if($reservation -ne $null)
- {
- Notify-NoWritePermissions -LockfilePath $lockfile_path -PermissionsObject $reservation
- return
- }
- # Now, actually try to make a reservation
- if((Reserve-WritePermissions -LockfilePath $lockfile_path) -eq $false)
- {
- # If this failed, it means someone made a reservation in between our first check, and our actual attempt.
- # Reserve-WritePermissions notifies the user
- return
- }
- try
- {
- $database = [XElement]::Load($database_path)
- $switchesnode = $database.Element("Switches")
- $hostname = Read-Host "Enter the new hostname ('quit' to quit)"
- while($hostname -ne "quit")
- {
- $switchesnode.Add([XElement]::new([XName]"Switch", [XAttribute]::new([XName]"Hostname", $hostname)))
- $hostname = Read-Host "Enter the new hostname ('quit' to quit)"
- }
- if((CommitOrCancel-Changes -Database $database -DatabasePath $database_path -LockfilePath $lockfile_path -Commit $true) -eq $false)
- {
- Write-Host "Something went wrong... $($_.Exception.Message)" -ForegroundColor Red
- Write-Host "Reverting changes..." -ForegroundColor Red
- if((CommitOrCancel-Changes -Database $database -DatabasePath $database_path -LockfilePath $lockfile_path -Commit $false) -eq $false)
- {
- Write-Host "*** Was not able to release the file lock. Open $lockfile_path and ensure it is reserved to you. If so, delete that file. ***" -ForegroundColor Red
- }
- }
- }
- catch
- {
- Write-Host "Something went wrong... $($_.Exception.Message)" -ForegroundColor Red
- Write-Host "Reverting changes..." -ForegroundColor Red
- if((CommitOrCancel-Changes -Database $database -DatabasePath $database_path -LockfilePath $lockfile_path -Commit $false) -eq $false)
- {
- Write-Host "*** Was not able to release the file lock. Open $lockfile_path and ensure it is reserved to you. If so, delete that file. ***" -ForegroundColor Red
- }
- }
- }
- function Open-Read()
- {
- Param
- (
- [Parameter(Mandatory)]
- [Alias("DatabasePath")]
- [string]$database_path
- )
- $database = [XElement]::Load($database_path)
- if($database -eq $null)
- { return }
- $switchesnode = $database.Element("Switches")
- foreach($switch in $switchesnode.Elements())
- {
- Write-Host $switch.Attribute("Hostname").Value
- }
- }
- $filename = "C:\Temp\database.xml"
- $lockfile = "C:\Temp\file_lock.txt"
- cls
- Write-Host "1.) Open Read-only, query switches"
- Write-Host "2.) Open Read-Write, add switches"
- $option = Read-Host "Enter an option"
- if($option -eq '1')
- {
- Open-Read -DatabasePath $filename
- }
- else
- {
- Open-Write -DatabasePath $filename -LockfilePath $lockfile
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement