Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #We assume that IP, MAC and name of USBIP host may be changed at any time.
- #Also we need to catch event when shared device disappears by any cause
- #and try to reconnect
- #Set input parameters
- param (
- $USBIP_hostname, #or CNAME
- $USBIP_portnumber, # For USBIP it is 3240 TCP by default.
- $VendorID, # It maybe "Aladdin" or "0529:"
- $USBIP_clientname # Name of USBIP client executable. It is usually named as "usbip.exe".
- )
- IF ($USBIP_hostname -eq $null)
- {
- $USBIP_hostname = "usboip"
- #If name(s) of target host(s) is (are) not given as argument, script will prompt you for input.
- #$USBIP_hostname = Read-Host "Enter hostname here"
- } #end IF
- IF ($USBIP_portnumber -eq $null)
- {
- $USBIP_portnumber = 3240
- #If port number is not given as argument, script will prompt you for input.
- #$USBIP_portnumber = read-host "Enter port number here"
- } #end IF
- IF ($VendorID -eq $null)
- {
- $VendorID = "Aladdin"
- #If name of vendor is not given as argument, script will prompt you for input.
- #$VendorID = Read-Host "Enter Vendor_ID here"
- } #end IF
- IF ($USBIP_clientname -eq $null)
- {
- $USBIP_clientname = "usbip.exe"
- #If name of executable is not given as argument, script will prompt you for input.
- #$USBIP_clientname = Read-Host "Enter name of USBIP client executable here"
- } #end IF
- #Get path to current script. Yes, this script should be placed in same dir with USBIP client.
- $scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
- $CurrentTime = Get-Date -UFormat "%Y-%m-%d-%H-%M-%S"
- $LogFile = "$scriptPath\LOG-$CurrentTime.log"
- #Get IP by hostname. IP is shown at parameter "IPAddressToString", so we'll select this parameter only:
- $USBIP_inetaddr=[System.Net.Dns]::GetHostAddresses("$USBIP_hostname") |
- Select-Object IPAddressToString -expandproperty IPAddressToString
- #We can get MAC from DHCP lease, but only if
- # 1) PS tools for DHCP are installed;
- # 2) account is included to "DHCP Users" group.
- #Don't forget to specify name of DHCP server.
- $USBIP_macaddr=Get-DhcpServerv4Lease -ComputerName (Get-DhcpServerInDC |
- Select-Object DnsName -ExpandProperty DnsName) -IPAddress $USBIP_inetaddr |
- Select-Object -ExpandProperty ClientId
- #===================================================================
- # All about logs and logrotating functions were copied from
- # https://gist.github.com/barsv/85c93b599a763206f47aec150fb41ca0
- # all logging settins are here on top
- $logLevel = "DEBUG" # ("DEBUG","INFO","WARN","ERROR","FATAL")
- $logSize = 1mb # 30kb
- $logCount = 30
- # end of settings
- function Write-Log-Line ($line) {
- Add-Content $logFile -Value $Line
- Write-Host $Line
- }
- # http://stackoverflow.com/a/38738942
- Function Write-Log {
- [CmdletBinding()]
- Param(
- [Parameter(Mandatory=$True)]
- [string]
- $Message = $msg,
- [Parameter(Mandatory=$False)]
- [String]
- $Level = "DEBUG"
- )
- $levels = ("DEBUG","INFO","WARN","ERROR","FATAL")
- $logLevelPos = [array]::IndexOf($levels, $logLevel)
- $levelPos = [array]::IndexOf($levels, $Level)
- $Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss:fff")
- if ($logLevelPos -lt 0){
- Write-Log-Line "$Stamp ERROR Wrong logLevel configuration [$logLevel]"
- }
- if ($levelPos -lt 0){
- Write-Log-Line "$Stamp ERROR Wrong log level parameter [$Level]"
- }
- # if level parameter is wrong or configuration is wrong I still want to see the
- # message in log
- if ($levelPos -lt $logLevelPos -and $levelPos -ge 0 -and $logLevelPos -ge 0){
- return
- }
- $Line = "$Stamp $Level $Message"
- Write-Log-Line $Line
- }
- # https://gallery.technet.microsoft.com/scriptcenter/PowerShell-Script-to-Roll-a96ec7d4
- function Reset-Log
- {
- # function checks to see if file in question is larger than the paramater specified
- # if it is it will roll a log and delete the oldes log if there are more than x logs.
- param([string]$fileName, [int64]$filesize = 1mb , [int] $logcount = 30)
- $logRollStatus = $true
- if(test-path $filename)
- {
- $file = Get-ChildItem $filename
- if((($file).length) -ige $filesize) #this starts the log roll
- {
- $fileDir = $file.Directory
- #this gets the name of the file we started with
- $fn = $file.name
- $files = Get-ChildItem $filedir | ?{$_.name -like "$fn*"} | Sort-Object lastwritetime
- #this gets the fullname of the file we started with
- $filefullname = $file.fullname
- #$logcount +=1 #add one to the count as the base file is one more than the count
- for ($i = ($files.count); $i -gt 0; $i--)
- {
- #[int]$fileNumber = ($f).name.Trim($file.name) #gets the current number of
- # the file we are on
- $files = Get-ChildItem $filedir | ?{$_.name -like "$fn*"} | Sort-Object lastwritetime
- $operatingFile = $files | ?{($_.name).trim($fn) -eq $i}
- if ($operatingfile)
- {$operatingFilenumber = ($files | ?{($_.name).trim($fn) -eq $i}).name.trim($fn)}
- else
- {$operatingFilenumber = $null}
- if(($operatingFilenumber -eq $null) -and ($i -ne 1) -and ($i -lt $logcount))
- {
- $operatingFilenumber = $i
- $newfilename = "$filefullname.$operatingFilenumber"
- $operatingFile = $files | ?{($_.name).trim($fn) -eq ($i-1)}
- write-host "moving to $newfilename"
- move-item ($operatingFile.FullName) -Destination $newfilename -Force
- }
- elseif($i -ge $logcount)
- {
- if($operatingFilenumber -eq $null)
- {
- $operatingFilenumber = $i - 1
- $operatingFile = $files | ?{($_.name).trim($fn) -eq $operatingFilenumber}
- }
- write-host "deleting " ($operatingFile.FullName)
- remove-item ($operatingFile.FullName) -Force
- }
- elseif($i -eq 1)
- {
- $operatingFilenumber = 1
- $newfilename = "$filefullname.$operatingFilenumber"
- write-host "moving to $newfilename"
- move-item $filefullname -Destination $newfilename -Force
- }
- else
- {
- $operatingFilenumber = $i +1
- $newfilename = "$filefullname.$operatingFilenumber"
- $operatingFile = $files | ?{($_.name).trim($fn) -eq ($i-1)}
- write-host "moving to $newfilename"
- move-item ($operatingFile.FullName) -Destination $newfilename -Force
- }
- }
- }
- else
- { $logRollStatus = $false}
- }
- else
- {
- $logrollStatus = $false
- }
- $LogRollStatus
- }
- # to null to avoid output
- $Null = @(
- Reset-Log -fileName $logFile -filesize $logSize -logcount $logCount
- )
- #===================================================================
- function Test-Port()
- #Copied from https://stackoverflow.com/a/22553267
- {
- $msg = "Trying to get IP from hostname"
- Write-Log "$msg" "INFO"
- IF ("$USBIP_inetaddr" -ne "")
- {
- $msg = "IP of $USBIP_hostname resolved as $USBIP_inetaddr"
- Write-Log "$msg" "INFO"
- }
- ELSE
- {
- $msg = "IP of $USBIP_hostname cannot be resolved"
- Write-Log "$msg" "ERROR"
- }
- $msg = "Trying to get MAC from hostname"
- Write-Log "$msg" "INFO"
- IF ("$USBIP_macaddr" -ne "")
- {
- $msg = "MAC of $USBIP_hostname resolved as $USBIP_macaddr"
- Write-Log "$msg" "INFO"
- }
- ELSE
- {
- $msg = "MAC of $USBIP_hostname cannot be resolved"
- Write-Log "$msg" "ERROR"
- }
- $TcpClient = New-Object Net.Sockets.TcpClient
- # We use Try\Catch to remove exception info from console if we can't connect
- try
- {
- $TcpClient.Connect($USBIP_inetaddr,$USBIP_portnumber)
- } catch
- {
- $msg = "Cannot connect to $USBIP_portnumber on $USBIP_hostname!"
- Write-Log "$msg" "ERROR"
- }
- IF($TcpClient.Connected)
- {
- $TcpClient.Close()
- $msg = "Port $USBIP_portnumber is operational"
- Write-Log "$msg" "INFO"
- DeviceList
- Sleep 10
- $msg = "Start watching"
- Write-Log "$msg" "INFO"
- Sleep 10
- WatchDevices #See below.
- } #endIF
- ELSE
- {
- $msg = "Port $USBIP_portnumber on $USBIP_inetaddr is closed, "
- $msg += "or host is unavailable. Trying to wake it up..."
- Write-Log "$msg" "ERROR"
- #Send WOL. See below.
- Wake-On-LAN $USBIP_macaddr
- #Wait for start
- $msg = "WOL sent to $USBIP_macaddr. Wait for a minute..."
- Write-Log "$msg" "INFO"
- Sleep 60
- #Probably we can't call function from itself. So we assuming that host is up
- #and devices are shared. Trying to enumerate.
- $msg = "Trying to list shared devices"
- Write-Log "$msg" "INFO"
- DeviceList #See below.
- #And then watch if device will be disappeared.
- $msg = "Start watching"
- Write-Log "$msg" "INFO"
- Sleep 10
- WatchDevices #See below.
- }
- }
- #https://www.pdq.com/blog/wake-on-lan-wol-magic-packet-powershell/
- function Wake-On-LAN()
- {
- #Send magic paket.
- #WOL packet is a byte array with 6 bytes of value 255 and then 16 repetitions
- #of the MAC address as it shown below:
- $MacByteArray = $USBIP_macaddr -split "[:-]" | ForEach-Object { [Byte] "0x$_"}
- [Byte[]] $MagicPacket = (,0xFF * 6) + ($MacByteArray * 16)
- #Create object UdpClient from .NET class
- $UdpClient = New-Object System.Net.Sockets.UdpClient
- #Connect UdpClient with broadcast address and UDP port 7 (maybe 0, 7, 9)
- $UdpClient.Connect(([System.Net.IPAddress]::Broadcast),7)
- #Send WOL sequence. We don't need an output at stdout.
- $UdpClient.Send($MagicPacket,$MagicPacket.Length) | Out-Null
- #And close connection
- $UdpClient.Close()
- }#Done.
- function DeviceList() #Gets list of shared devices
- {
- #Copied from https://stackoverflow.com/a/8762068
- #Create new process
- $USBIPlistpinfo = New-Object System.Diagnostics.ProcessStartInfo
- #Set filename with path
- $USBIPlistpinfo.FileName = "$scriptPath\$USBIP_clientname"
- #Set redirect of stderr from where we'll get info about shared devices
- $USBIPlistpinfo.RedirectStandardError = $true
- #
- $USBIPlistpinfo.UseShellExecute = $false
- #Set working directory
- $USBIPlistpinfo.WorkingDirectory = "$scriptPath"
- #Give args to .EXE
- $USBIPlistpinfo.Arguments = "-l $USBIP_hostname"
- #Start process
- $USBIPlistOutput = New-Object System.Diagnostics.Process
- $USBIPlistOutput.StartInfo = $USBIPlistpinfo
- #Disable window
- $USBIPlistOutput.Start() | Out-Null
- #Set variable for raw stderr output
- $USBIPlistStdErr = $USBIPlistOutput.StandardError.ReadToEnd()
- #And then split it to lines and convert into array.
- $devlistraw = $USBIPlistStdErr.Split(")")
- $devArray=@($devlistraw)
- $msg = "$USBIPlistStdErr"
- $msg += "Trying to mount..."
- Write-Log "$msg" "INFO"
- #Call function which mounts all devices. Maybe.
- MountAll
- }
- function MountAll()
- {
- ForEach ($device in $devArray)
- {
- #Filter output by $VendorID.
- IF ($device -match $VendorID)
- {
- #get chars before 1st ":"
- $separator = $device.IndexOf(":")
- #remove unnesessary CR/LF
- $busID = ($device.Substring(0,$separator) -replace "\s+","") -replace "-$USBIP_hostname",""
- #mount device with given bus ID
- MountNthDevice
- } #endIF
- }
- #report if OK
- $msg = "Device with Bus ID $busID mounted"
- Write-Log "$msg" "INFO"
- }
- function MountNthDevice() #Mounts devices of specified vendor
- {
- $USBIPmount = New-Object System.Diagnostics.ProcessStartInfo
- $USBIPmount.FileName = "$scriptPath\$USBIP_clientname"
- $USBIPmount.RedirectStandardError = $true
- $USBIPmount.UseShellExecute = $false
- $USBIPmount.WorkingDirectory = "$scriptPath"
- $USBIPmount.Arguments = "-a $USBIP_hostname $busID"
- $USBIPmStart = New-Object System.Diagnostics.Process
- $USBIPmStart.StartInfo = $USBIPmount
- $USBIPmStart.Start() | Out-Null
- }
- function WatchDevices()
- {
- #Get list of mounted devices and filter by "CompatibleID"
- $GetMntList = gwmi Win32_USBControllerDevice |%{[wmi]($_.Dependent)} |
- Sort Manufacturer,Description,DeviceID |
- Select-Object CompatibleID -ExpandProperty CompatibleID
- #While device with target ID will be present
- WHILE ($GetMntList -like "*$VendorID*")
- {
- $msg = "Devices are present"
- Write-Log "$msg" "INFO"
- #Set timeout
- Sleep 300
- #And try to list devices again
- $GetMntList = gwmi Win32_USBControllerDevice |%{[wmi]($_.Dependent)} |
- Sort Manufacturer,Description,DeviceID |
- Select-Object CompatibleID -ExpandProperty CompatibleID
- }
- #If device was unmounted...
- $msg = "Devices not found! Trying to reconnect..."
- Write-Log "$msg" "ERROR"
- #return to connection testing
- Test-Port
- }
- #Start with check port availability
- $msg = "Start execution with connectivity testing to $USBIP_hostname"
- Write-Log "$msg" "INFO"
- Test-Port
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement