func_Start-AlocVMM2DVLSSync.ps1
<#
.Synopsis Syncs data from System Center Virtual Machine Manger to Remote Desktop Manager .Description This function gets the information of all VM's in SC VMM an sync over to RDM If the entry isn't found in RDM the entry will be created in the specified folder. .Parameter DataSourceName Name of the RDM Datasource to connect to. Only required if you run this headless and there is 2 or more data sources, as the script then prompt to as which data source to connect to. .Parameter VMMFQDN Full dns name of the VMMServer to get VM's from .Parameter VMGroup The path to the folder where new VM's wil be created .Example Sync-VMM2DVLS -VMMFQDN "SCVMM01.domain.com" -VMGroup "SCVMM\NewVMs" #> function GLOBAL:Start-AlocVMM2DVLSSync { [CmdletBinding()] param ( # Name of the RDM Datasource [Parameter( Mandatory = $True, ParameterSetName = "ReuseInjectAppKey", HelpMessage = "Name of the RDM Datasource" )] [Parameter( Mandatory = $True, ParameterSetName = "CreateDataSource", HelpMessage = "Name of the RDM Datasource" )] [Alias("DataSourceName")] [String] $DSName, # Full dns name of the VMMServer to get VM's from [Parameter( Mandatory = $True, ParameterSetName = "Reuse", HelpMessage = "Full dns name of the VMMServer to get VM's from" )] [Parameter( Mandatory = $True, ParameterSetName = "ReuseInjectAppKey", HelpMessage = "Full dns name of the VMMServer to get VM's from" )] [Parameter( Mandatory = $True, ParameterSetName = "CreateDataSource", HelpMessage = "Full dns name of the VMMServer to get VM's from" )] [Alias("VMMFQDN")] [String] $VMMServerName, # The path to the folder where new VM's wil be created [Parameter( Mandatory = $True, ParameterSetName = "Reuse", HelpMessage = "The path to the folder where new VM's wil be created" )] [Parameter( Mandatory = $True, ParameterSetName = "ReuseInjectAppKey", HelpMessage = "The path to the folder where new VM's wil be created" )] [Parameter( Mandatory = $True, ParameterSetName = "CreateDataSource", HelpMessage = "The path to the folder where new VM's wil be created" )] [Alias("VMGroup")] [String] $BaseGroup, # Application key from Devolutions server [Parameter( Mandatory = $True, ParameterSetName = "ReuseInjectAppKey", HelpMessage = "Application key from Devolutions server" )] [Parameter( Mandatory = $True, ParameterSetName = "CreateDataSource", HelpMessage = "Application key from Devolutions server" )] [String] $AppKey, # Application Secret from Devolutions server [Parameter( Mandatory = $True, ParameterSetName = "ReuseInjectAppKey", HelpMessage = "Application Secret from Devolutions server" )] [Parameter( Mandatory = $True, ParameterSetName = "CreateDataSource", HelpMessage = "Application Secret from Devolutions server" )] [String] $AppSecret, # If set, a datasource will be created instead of using an existing [Parameter( Mandatory = $True, ParameterSetName = "CreateDataSource", HelpMessage = "If set, a datasource will be created instead of using an existing" )] [Switch] $CreateDS, # Name of the DVLS server [Parameter( Mandatory = $True, ParameterSetName = "CreateDataSource", HelpMessage = "Name of the DVLS server" )] [Alias("Hostname")] [string] $DVLSHostname, # Tries to get extended inofrmation from the VMs [Parameter( Mandatory = $False, ParameterSetName = "Reuse", HelpMessage = "If specified, extra information is tried to be collected." )] [Parameter( Mandatory = $False, ParameterSetName = "ReuseInjectAppKey", HelpMessage = "If specified, extra information is tried to be collected." )] [Parameter( Mandatory = $False, ParameterSetName = "CreateDataSource", HelpMessage = "If specified, extra information is tried to be collected." )] [Switch] $ExtendedInfo ) if ($CreateDS) { $DSAction = "CreateDataSource" }elseif ($DSName -ne "") { $DSAction = "ReuseInjectAppKey" }else { $DSAction = "Reuse" } $PrevErrorActionPreference = $ErrorActionPreference $ErrorActionPreference = "Stop" $PrePadding = " ----VMM-Desc---- " $PostPadding = " ----VMM-End---- " $VerbosePref = $VerbosePreference $VerbosePreference = "SilentlyContinue" if ((Get-Module).Name -notcontains "RemoteDesktopManager") { if ((Get-Module -ListAvailable).Name -contains "RemoteDesktopManager") { try { Write-Verbose "Importing RemoteDesktopManager" Import-Module RemoteDeskTopManager } catch { Write-Error "Failed to import RemoteDesktopManager" } }else{ try { Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Scope CurrentUser -Force Install-Module RemoteDesktopManager -Scope CurrentUser -Force } catch { Write-Error "RemoteDesktopManager Module not installed, and installation failed." } } } $VerbosePreference = $VerbosePref Write-Verbose "Connecting to Devolutions Server" $DataSources = Get-RDMDataSource switch ($DSAction) { "Reuse" { if ($DataSources.Count -gt 1) { Write-Host "Select the data source to connect to:" $i = 0 foreach ($DataSource in $DataSources) { Write-Host "$($i): $($DataSource.Name)" $i++ } [int]$Selection = Read-Host "Enter Number" Set-RDMCurrentDataSource -DataSource $DataSources[$Selection] }else { Set-RDMCurrentDataSource -DataSource $DataSources[0] } } "ReuseInjectAppKey" { try { Write-Verbose "Using datasource $DSName and specified Key/Secret" $Currentds = Get-RDMDataSource $DSName Set-RDMCurrentDataSource $Currentds Set-RDMDatasourceProperty $Currentds -Property "ScriptingTenantID" -Value $AppKey Set-RDMDatasourceProperty $Currentds -Property "ScriptingApplicationPassword" -Value $AppSecret if ($VerbosePreference = "Continue") { Get-RDMDatasourceProperty $Currentds -Property "ScriptingTenantID" Get-RDMDatasourceProperty $Currentds -Property "ScriptingApplicationPassword" } Set-RDMCurrentDataSource $Currentds } catch { Write-Error "The datasource supplied could not be found." } } "CreateDataSource" { Write-Verbose "Creating datasource $DSName" if ($DataSources.Name.Contains($DSName)) { Remove-RDMDataSource $DSName } if ($DVLSHostname.Substring(0,8).ToLower() -ne "https://"){ $DVLSHostname = "https://$DVLSHostname" } $ds = New-RDMDataSource -DVLS -Server $DVLSHostname -Name $DSName -ScriptingTenantID $AppKey -ScriptingApplicationPassword $AppSecret if ($VerbosePreference = "Continue") { Get-RDMDatasourceProperty $ds -Property "ScriptingTenantID" Get-RDMDatasourceProperty $ds -Property "ScriptingApplicationPassword" } Set-RDMCurrentDataSource $ds } } if ($Currentds.IsConnected -eq $True -and $Currentds.IsOffline -eq $false) { Write-Verbose "Connected to RDM, datasource $($Currentds.Name)" $RDMHosts = Get-RDMSession }else{ try { $RDMHosts = Get-RDMSession } catch { Get-RDMCurrentDataSource Write-Error "Connection ot RDM, datasource $($Currentds.Name) not ready, script exits" exit } } Try { # Expecting Domain, so trying default connection to VMM Server Write-Verbose "Connecting to VMM server..." $PSSession = New-PSSession -ComputerName $VMMServerName } Catch { # Domain login failed, trying negotiate try { if (Test-Path .\vmmcred.clixml) { $Creds = Import-Clixml .\vmmcred.clixml $PSSession = New-PSSession -ComputerName $VMMServerName -Credential $Creds }else { Write-Warning "Kerberos autentication failed, and no .\vmmcred.clixml file exists Please create a vmmcred.clixml file with credenetials to access to VMM Server by running, in the same directory at this script Get-Credential | Export-Clixml .\vmmcred.clixml" exit } } catch { $Message = 'Cannot connect to VMM Server: {0} Possible solution is to run, in an Elevated Powershell winodws: "Set-Item WSMan:\localhost\Client\TrustedHosts\ -Value {0}" The script will now end.' -f $VMMServerName Write-Error -Message $Message Exit } } Write-Verbose "Connected to VMM" Write-Verbose "Getting list of VMs from VMM" $VMs = Invoke-Command -Session $PSSession -ArgumentList $VMMServerName -ScriptBlock {Get-SCVirtualMachine -VMMServer $Args[0]} Remove-PSSession -Session $PSSession Write-Verbose "List Retrieved" #$VMs = @(@{Name = "Server1"; Description = "This is the first server"; ComputerName = "Server1.aloc.com"},@{Name = "Server2"; Description = "This is server two"; ComputerName = "Server1.aloc.com"}) ForEach ($VM in $VMs | Where-Object {$_.name -notlike "SLOT-[0-9][0-9][0-9]" -or $_.Name -notlike "VM-[0-9][0-9]" -or $_.name -notlike "NP-[0-9][0-9]" -or $_.name -notlike "SP-[0-9][0-9]"}){ if ($null -eq $VM.ComputerName -or $VM.ComputerName -eq "") { Write-Debug "Skipping $($VM.Name) No hostname" Continue }elseif (($VMs | Where-Object {$_.Name -eq $VM.Name}).count -gt 1) { Write-Debug "Skipping $($VM.Name) Multiple VM instances" Continue } $RDMHost = $RDMHosts | Where-Object {$_.Host -eq $VM.ComputerName -and $_.ConnectionType -eq "Group" -and $_.GroupDetails.GroupType -eq "Server"} $RDMName = $RDMHosts | Where-Object {$_.Name -eq $VM.Name -and $_.ConnectionType -eq "Group" -and $_.GroupDetails.GroupType -eq "Server"} if ($RDMHost.Count -eq 1) { $Action = "Edit" }elseif ($RDMName.Count -eq 1) { $RDMHost = $RDMName $Action = "Edit" }elseif ($RDMHost.Count -gt 1 -and $RDMName.Count -gt 1) { Write-Debug "Skipping $($VM.Name)/$($VM.ComputerName), multiple RDM entries found" }elseif ($RDMHost.Count -eq 0 -and $RDMName.Count -eq 0){ $Action = "NewEntry" }else{ Write-Debug "Cant choose action for $($VM.Name)/$($VM.ComputerName)" $Action = "None" } if ($Action -eq "Edit") { if ($($RDMHost.Description -match ("----VMM-Desc----") -and $RDMHost.Description -match ("----VMM-End----"))){ $Action = "Edit" }else { $Action = "FirstEdit" } } Write-Verbose "Action selected: $Action" if ($Action -eq "Edit" -or $Action -eq "FirstEdit") { Write-Verbose "Updating host: $($VM.Name)" try { $N = ([regex]::Matches($RDMHost.Description, "----VMM-Desc----" )).count if ($N -gt 1) { $Start = $($RDMHost.Description).IndexOf("----VMM-Desc----") $End = $($RDMHost.Description).LastIndexOf("----VMM-End----") $Begining = $RDMHost.Description.Substring(0,$Start).trim() $Last = $RDMHost.Description.Substring($End+15).Trim() $RDMHost.Description = " $Begining ----VMM-Desc---- ----VMM-End---- $Last".Trim() $RDMHost.Description = $RDMHost.Description -replace (" ","") $Action = "Edit" } if ($Action -eq "FirstEdit") { $RDMHost.Description = $RDMHost.Description + $PrePadding + $VM.Description + $PostPadding }else{ $HostDesc = $RDMHost.Description $NewDesc = $HostDesc.Substring(0,$HostDesc.IndexOf("----VMM-Desc----")+18) $NewDesc += $VM.Description $NewDesc += $HostDesc.Substring(($HostDesc.IndexOf("----VMM-End----"))-2,$HostDesc.Length-($HostDesc.IndexOf("----VMM-End----")-2)) $RDMHost.Description = $NewDesc } Write-Verbose "Updating variable" $RDMHost.Group = $RDMHost.Group -replace ($RDMHost.name,$VM.Name) $RDMHost.Name = $VM.name $RDMHost.Host = $VM.ComputerName } catch { Write-Error "Failed to update variables $_" } try { Write-Verbose "Saving to RDM" Set-RDMSession $RDMHost -Refresh } catch { Write-Error "Failed to save entry $_" } }Elseif ($Action = "NewEntry") { if ($VM.name -like "SLOT-[0-9][0-9][0-9]" -or $VM.Name -like "VM-[0-9][0-9]" -or $VM.name -like "NP-[0-9][0-9]" -or $VM.name -like "SP-[0-9][0-9]") { Write-Verbose "Booking slot, skipping" Continue } Write-Verbose "Entry not found, creating: $($VM.Name)" try { $DefaultInfo = 'HOST: $HOST$ IP: $COMPUTER_IP$' $NewSession = New-RDMSession -Type Group -Name $VM.Name -Host $VM.ComputerName -Group $BaseGroup $NewSession.GroupDetails.GroupType = "Server" $NewSession.CredentialConnectionID = "1310CF82-6FAB-4B7A-9EEA-3E2E451CA2CF" $NewSession.Description = $DefaultInfo + $PrePadding + $VM.Description + $PostPadding if ($ExtendedInfo) { #$ExtendedInfomation | fl -Property * $ExtendedInfomation = Start-AlocExtendedScan $vm.ComputerName $NewSession.MetaInformation = $ExtendedInfomation.OperatingSystem } } catch { Write-Error "Failed to create varible $_" } try { Write-Verbose "Saving Host entry" Set-RDMSession $NewSession } catch { Write-Error "Failed to save to RDM $_ $($NewSession.Group)" } try { Write-Verbose "Create RDP Connection" $NewRDP = New-RDMSession -Type RDPConfigured -Name "RDP" -TemplateID "157fc699-d152-4c8b-a944-19be44c736e7" -Host "" -Group $NewSession.Group } catch { Write-Error "Failed to create RDP Connection" } try { Write-Verbose "Saving RDP Connection" Set-RDMSession $NewRDP } catch { Write-Error "Failed to save RDP Connection" } Write-Debug "Creation done." } } # Setting back system variables $VerbosePreference = $PrevVerbosePreference $ErrorActionPreference = $PrevErrorActionPreference } function Start-AlocExtendedScan { param ( # The Server FQDN to look up [Parameter(Mandatory = $true, Position = 0)] [String] $FQDN ) try { $CimS = New-CimSession -ComputerName $FQDN -Credential $Cred $Information = Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $CimS Remove-CimSession $CimS Return $Information } catch { Write-Warning "Extended information could not be retrieved" return $null } } |